Manuel Kaufmann (Humitos): Modifying a Django setting could be a nightmare

I've been working at Read the Docs for four months more or less at this time. Although I've been using Django for a decade now, there are many things that I never used, forget or don't know how they work internally.

During the last three or four weeks I worked in a new feature for the corporate site of Read the Docs (https://readthedocs.com/) and I had a lot of different problems: mainly because I didn't know the full codebase, but also because I never used some pieces of technology involved to make this feature.

So, what do you do when you are afraid of breaking everything? You write many test to cover your ass! That's what I did and I felt very comfortable when I started writing the logic of the feature itself --of course, to write the tests I had to ask many questions to my team to be sure the tests were accurate regarding what they were testing.

Finally, the PR was tested for some members of the team, everything worked as expected, the code was merged and deployed. Successful story, right?

One of two days later, I started seeing one of my tests related to that PR failing locally. I did a simple PR to run the test in CircleCI and it also failed there. "WTF? This doesn't make sense" -I thought. I did the manual QA locally and the code worked as expected but the test were failing but... It didn't make sense because the initial tests under CircleCI before merging the PR were passing and now without any change at all this specific test wasn't passing. I was very confused.

I went to the code of my tests to find something strange and after taking a look at this code I didn't find anything that called my attention directly but I found that I was mixing @override_settings and @modify_settings as decorators of the class. "That may be a reason... Really? Why?" -I was confused. I went to the documentation, search at Google to see if the first results could give some clue and after a couple of hours reading, thinking and shouting alone I realized that I was using both options of the @modify_settings decorator: append and remove which, in theory, is not a problem.

Note

What is the difference between @override_settings and @modify_settings? Well, one allows you to replace the setting completely and the other one allows you to append, prepend or remove values from the current value of the setting.

As I wanted to modify the MIDDLEWARE_CLASSES to inject a new one in the middle of the others, I needed to remove the ones that go after the one I wanted to inject and then add mine (the new one) plus the ones that I had removed. Am I right?

I'm sure that at this point I'm wrong and there should be a much better way of doing this, but I'm already writing the post :)

So, my code looks something like:

@modify_settings(MIDDLEWARE_CLASSES={
    'append': [
        'readthedocsinc.middleware.MyOwnMiddleware',
        'externallib.middleware.ExternalMiddleware',
    ],
    'remove': [
        'externallib.middleware.NoNeededMiddleware',
        'externallib.middleware.ExternalMiddleware',
    ],
})
class FooBar(TestCase):
    # ...

In my case, NoNeededMiddleware wasn't needed for the tests and it had to be completely removed. ExternalMiddleware was needed but MyOwnMiddleware should precede it; that's why I needed to first remove it and then append it -in another position in the list, though.

Anything wrong up to here? No. Well, yes. Oh... "No, the test are passing", or in a better way "The tests were passing right before the deploy but now there is one that it's not passing anymore"

At this point, I did what I learnt from my first boss in my professional career: I went to the Django source code of @modify_settings and I found the issue: it removes everything from remove key and appends everything from append key. Makes sense.

Now, which operation is executed first? AHA! Well, it depends since dictionaries don't have order (< Python 3.6), sometimes it could be remove and sometimes it could be append. So, I'd say that all the planets were aligned to pass all the tests locally and in CircleCI before merging, and after merging they got unaligned and the order started behaving in the other way :)

What I did? I just used collections.OrderedDict and put remove as the first element in the dictionary, and then append. That way, I'm 100% sure that first I'm removing the middlewares I don't need and then I'm adding the ones that I'm interested in the proper order.

The final code looks like this:

from collections import OrderedDict
@modify_settings(MIDDLEWARE_CLASSES=OrderedDict([
    (
        'remove',
        [
            'externallib.middleware.NoNeededMiddleware',
            'externallib.middleware.ExternalMiddleware',
        ],
    ).
    (
        'append',
        [
            'readthedocsinc.middleware.MyOwnMiddleware',
            'externallib.middleware.ExternalMiddleware',
        ],
    ),
]))
class FooBar(TestCase):
    # ...

I think this should be clearly detailed in the Django documentation of @modify_settings since the behaviour is way different and can cause a lot of time lost because of this --even worse if you are working with Python 2 which will randomly do one or the other first.

Facundo Batista: Eventos, eventos! Python en el primer semestre

Tenemos algunos eventos de Python Argentina en el primer semestre del año. Vayamos cronológicamente.

El miércoles 4 de Abril, 19hs, hacemos un meetup de Python Argentina en Devecoop. Tendremos un par de charlas técnicas, quizás hagamos un "Consultorio Python", veremos cómo lo armamos. Si no están anotados en el meetup de Python Buenos Aires, regístrense así reciben las noticias de estos meetups y se anotan fácil y etc.

Del 28 de Abril al 1 de Mayo tenemos una nueva edición del PyCamp, nuevamente en Baradero. Ya está abierta la inscripción, considerando incluso descuentos para socios de Python Argentina. Pueden buscar toda la info en la página del evento.

También tenemos dos PyDays, ambos en Mayo. Sí, dos, por ahora... habrán más en el año. El primero en La Plata, todavía pendiente de definir cual sábado, y el segundo en Corrientes, el sábado 19. Ya les traeré más noticias cuando nos acerquemos a las fechas.

Por otro lado, estamos armando la PyCon Argentina de este año en Buenos Aires. Fecha todavía no tenemos (estamos buscando el lugar, todavía) pero será Septiembre, Octubre o Noviembre.

Todo esto es en parte gracias a la Asociación Civil de Python Argentina, que nos permite tener un marco estructural con el cual movernos y que no nos venga la AFIP a meter en cana por mover guita por ahí... así que si querés apoyarnos en general considerá hacerte socia/o vos o ayudanos pasando este folleto en donde trabajes para que esa empresa/cooperativa lo considere también. Gracias!

Facundo Batista: Eventos, eventos! Python en el primer semestre


Tenemos algunos eventos de Python Argentina en el primer semestre del año. Vayamos cronológicamente.

El miércoles 4 de Abril, 19hs,  hacemos un meetup de Python Argentina en Devecoop. Tendremos un par de charlas técnicas, y quizás hagamos un "Consultorio Python", veremos cómo lo armamos. Si no están anotados en el meetup de Python Buenos Aires, regístrense así reciben las noticias de estos meetups y se anotan fácil y etc.

Del 28 de Abril al 1 de Mayo tenemos una nueva edición del PyCamp, nuevamente en Baradero. Ya está abierta la inscripción, considerando incluso descuentos para socios de Python Argentina. Pueden buscar toda la info en la página del evento.

También tenemos dos PyDays, ambos en Mayo. Sí, dos, por ahora... habrán más en el año. El primero en La Plata, todavía pendiente de definir cual sábado, y el segundo en Corrientes, el sábado 19. Ya les traeré más noticias cuando nos acerquemos a las fechas.

Por otro lado, estamos armando la PyCon Argentina de este año en Buenos Aires. Fecha todavía no tenemos (estamos buscando el lugar, todavía) pero será Septiembre, Octubre o Noviembre.

Todo esto es en parte gracias a la Asociación Civil de Python Argentina, que nos permite tener un marco estructural con el cual movernos y que no nos venga la AFIP a meter en cana por mover guita por ahí... así que si querés apoyarnos en general considerá hacerte socia/o vos o ayudanos pasando este folleto en donde trabajes para que esa empresa/cooperativa lo considere también. Gracias!

Marcelo Fernández: Taller de Programación de Sockets TCP/IP

En este mes de febrero tuve la suerte de llevar adelante en la UNLu un breve pero conciso taller de programación de sockets basado en Python. Dejo los slides, ejemplos de código y ejercicios planteados en el apartado de Charlas de mi blog, y en este post.

Agenda:

  • Clase 1: Introducción Sockets API. Modelo OSI, entornos de ejecución.Introducción a Python. Socket API para UDP. Ejercicios.
    • Descargar en Formato ODP / Formato PDF.
    • Código de ejemplo: ZIP.
  • Clase 2: Socket API para TCP. Código de ejemplo y ejercicios.
    • Descargar en Formato ODP / Formato PDF.
  • Clase 3: Multiprogramación, concurrencia, paralelismo. Syscall fork() y relacionados. Ejemplos de servidor multiproceso. Procesos vs. Threads.
    • Descargar en Formato ODP / Formato PDF.
    • Código de ejemplo: ZIP.
  • Clase 4: Sockets asincrónicos. Modelo de trabajo, syscall select(). Ejemplos de código. Introducción a Scapy.
    • Descargar en Formato ODP / Formato PDF.
    • Código de ejemplo: ZIP.

¡Saludos!

Facundo Batista: Vacaciones en familia, playa y sierras


Durante el veranito nos tomamos unos días con la familia para pasear por distintos lados.

Sí, hace un montón. Es que nos tardamos en procesar las fotos... no escala; para las próximas vacaciones largas, creo que voy a poner a la familia a revisar fotos durante las vacaciones mismas, sino llegamos y tenemos 1238941 fotos, y revisando un cachito durante la cena en los sucesivos días, no terminamos más... al punto incluso que todavía no están listas! Pero bueno, ya no espero más, saco este post, las fotos vendrán después...


Playa

Entre Navidad y Año Nuevo nos fuimos en carpa a Mar Azul. Apuntábamos al camping al que habíamos ido cuando Felipe era pequeño, pero ese ya no existe más y el único que quedó es el Camping de Los Ingenieros, que estuvo bastante bien (aunque el baño que teníamos cerca nunca tuvo agua caliente, y en general le faltan mesas).

La pasamos muy bien, aunque hizo mucho calor y en algunos momentos era agobiante (apenas sobrevivíamos bajo unas sombritas poco densas). Claro, está el mar para meterse, pero hay toda una franja horaria en la que no íbamos a llevar a los chicos a la playa para que se calcinen bajo el sol.

Preparándonos para ir a la playa

Almorzando en el camping

Obviamente fuimos en carpa, y nos dimos cuenta que ya es un poco chica para los cuatro. Eso, sumado a que se quebró una vara de la estructura y rasgó el techo, nos estaría forzando a comprar una carpa nueva más grande, tenemos que ver qué hay...

La playa de Mar Azul es muy linda, bastante ancha, y aunque en algunos momentos había bastante gente, nunca estuvimos amuchados (pero a veces se complicaba armar una cancha de tejo grande...).

Atardecer en la playa, el día que llegamos

Jugando al tejo con Felipe


Al Este de las Sierras

En Enero nos fuimos a Córdoba un par de semanas (bien en contra mano de "findes de semana" o "quincenas", para no desquiciarnos al viajar). Estuvimos unos días en El Espinillo, y después cruzamos las sierras y nos quedamos otros días en La Población.

Un minuto de tranquilidad :)

El primer lugar, en El Espinillo, era en un complejo de tres cabañas con una pileta compartida. La pileta estuvo muy bien, ya que esos días hizo mucho calor entonces los chicos se metieron varias veces y la disfrutaron un montón. Con Moni no nos metimos tanto pero aprovechamos para tomar sol. Incluso, como a veces la gente de las otras cabañas se iban temprano, tuve un par de días en los que pude tomar sol en bolas lo más tranquilo.

Además de la pileta, también hicimos "agua" en varios ríos cercanos (Del Espinillo, Del Medio, y Los Reartes)... algunos con más sombra, otros con más pastito alrededor, algunos con el piso de piedra, en otros teníamos playita de arena... muchas combinaciones, lo importante era que nos podíamos meter un rato al agua, tomar sol, disfrutar el verde, pasarla bien.

Los chicos disfrutando la pileta a full

En un arroyo de por ahíEn un arroyo de por ahí

Uno de los días fuimos a visitar la Villa General Belgrano. Estuvo bueno porque visitamos el Museo Politemático Castillo Romano y paseamos un rato, pero el restaurant al qué íbamos siempre ya no es lo que era (la cerveza artesanal como aguada, la comida meh, la atención dejó que desear) y en general es una ciudad "demasiado turística" a la que no llegamos a disfrutar.

Un paseo que sí nos encantó de esos días fue el del Parque Recreativo de La Serranita, un lugar bárbaro con mil juegos y actividades. Hicimos minigolf, arquería, futpool, jugamos al tejo, carrera de bolitas, nos tiramos por un tobogán gigante, recorrimos un laberinto, hicimos actividades de treparse y equilibrio, adivinanzas y un montón de actividades más... estuvimos como seis horas ahí adentro (sin contar el almuerzo), súper recomendado para ir con la familia!

Practicando el mini-golf

Felipe atacando un helado con ganas

Otra visita que disfrutamos fue a Nico y Jesi en La Quintana, donde pasamos una tarde bárbara charlando y tomando mate. Estuvo complicado llegar porque ya en viaje nos agarró una lluvia torrencial, y cuando llegamos a La Quintana los caminos estaban complicados... no sólo por el barro, sino también porque la lluvia había sido tanta que cada calle era un pequeño arroyo.

Encima tuve la suerte de presenciar (y casi participar!) en la instalación del primer prototipo funcional del LibreRouter en su antena, :D

Visitando La Quintana

En el monumento a Mercedes Sosa


Las Sierras, lado Oeste

A mitad de las vacaciones cambiamos de lugar. Hicimos un pequeño viaje cruzando las sierras y nos fuimos hasta el segundo lugar que teníamos alquilado.

Era una casita mediana, súper equipada, en el medio de un inmenso terreno, cerca de una casa bien grande que era donde vivía la dueña. El paisaje era muy lindo, la verdad, todo muy cuidado, verde por doquier, hermoso.

Los peques, contemplando el paisaje

Foto grupal en una de las construcciones de la Villa

Los días de la segunda fase estuvieron en general más frescos, lo que nos llevó a realizar menos actividades "acuáticas", pero no por eso aprovechamos menos las vacaciones: además de un par de veces en la pileta, y algunas en ríos/arroyos, "pancheamos" a full y paseamos algo.

A nivel de chapoteo, nos fuimos una vez a un Balneario en Paso de las Tropas, cerca de Nono, con la idea de almorzar, pasar la tarde, y luego apuntar para el Museo Rocsen, pero se nos fueron pasando las horas y después ya estábamos muy cansados, así que nos volvimos, dejamos el museo para la próxima. También encontramos una zona linda para aprovechar un arroyo cerca de donde nos hospedábamos (recorrimos un caminito con el auto hasta que no se pudo más, y luego un tramo a pie siguiendo el arroyo, hasta llegar a una linda zona para pasar la tarde). La verdad es que la primera vez nos quedamos en un punto con una pequeña cascadita, pero la segunda vez como cuando llegamos ya había gente, seguimos caminando un poco más y encontramos un lugar mejor :)

En un arroyito con unas cascadas hermosas

Preparando el almuerzo al costado del agua

Con respecto a los paseos, fuimos varias veces a la Plaza de San Javier, unos kilómetros al norte. No sólo para las compras de supermercado y eso, sino porque había feria artesanal todos los días, entonces visitamos varias veces, e incluso caimos de casualidad en una obra de títeres que estuvo muy buena. Encima era una zona donde había varios lugares lindos para comer, e incluso un pequeño parque cervecero/heladería, al cual fuimos más de una vez :)

También hicimos varios kilómetros para el sur y visitamos la fábrica de aceite de oliva Sierra Pura. Nos encantó. Te reciben, te muestran los árboles contándote las diferencias entre los tipos de olivo que hay, luego te muestran las máquinas con las que producen, y te explican todo el proceso, contestándote las preguntas que se te ocurran. Como no hay turnos ni horarios, llegás, y al rato ya te hacen el paseo, sean 3, 7, o 15 personas. Al final, hay una degustación de todos los aceites que hacen (tres blends, tres varietales, y muchos saborizados), y obvio uno puede comprar ahí con algún descuento :)

Malena, disfrutando del aire libre

En fin. Vacaciones, paseo, descanso. Ahora de nuevo en la jungla, desde hace rato...

Facundo Batista: Vacaciones en familia, playa y sierras

Durante el veranito nos tomamos unos días con la familia para pasear por distintos lados.

Sí, hace un montón. Es que nos tardamos en procesar las fotos... no escala; para las próximas vacaciones largas, creo que voy a poner a la familia a revisar fotos durante las vacaciones mismas, sino llegamos y tenemos 1238941 fotos, y revisando un cachito durante la cena en los sucesivos días, no terminamos más... al punto incluso que todavía no están listas!

Playa

Entre Navidad y Año Nuevo nos fuimos en carpa a Mar Azul. Apuntábamos al camping al que habíamos ido cuando Felipe era pequeño, pero ese ya no existe más y el único que quedó es el Camping de Los Ingenieros, que estuvo bastante bien (aunque el baño que teníamos cerca nunca tuvo agua caliente, y en general le faltan mesas).

La pasamos muy bien, aunque hizo mucho calor y en algunos momentos era agobiante (apenas sobrevivíamos bajo unas sombritas poco densas). Claro, está el mar para meterse, pero hay toda una franja horaria en la que no íbamos a llevar a los chicos a la playa para que se calcinen bajo el sol.

Preparándonos para ir a la playaAlmorzando en el camping

Obviamente fuimos en carpa, y nos dimos cuenta que ya es un poco chica para los cuatro. Eso, sumado a que se quebró una vara de la estructura y rasgó el techo, nos estaría forzando a comprar una carpa nueva más grande, tenemos que ver qué hay...

La playa de Mar Azul es muy linda, bastante ancha, y aunque en algunos momentos había bastante gente, nunca estuvimos amuchados (pero a veces se complicaba armar una cancha de tejo grande...).

Atardecer en la playa, el día que llegamosJugando al tejo con Felipe

Al Este de las Sierras

En Enero nos fuimos a Córdoba un par de semanas (bien en contra mano de "findes de semana" o "quincenas", para no desquiciarnos al viajar). Estuvimos unos días en El Espinillo, y después cruzamos las sierras y nos quedamos otros días en La Población.

Un minuto de tranquilidad :)

El primer lugar, en El Espinillo, era en un complejo de tres cabañas con una pileta compartida. La pileta estuvo muy bien, ya que esos días hizo mucho calor entonces los chicos se metieron varias veces y la disfrutaron un montón. Con Moni no nos metimos tanto pero aprovechamos para tomar sol. Incluso, como a veces la gente de las otras cabañas se iban temprano, tuve un par de días en los que pude tomar sol en bolas lo más tranquilo.

Además de la pileta, también hicimos "agua" en varios ríos cercanos (Del Espinillo, Del Medio, y Los Reartes)... algunos con más sombra, otros con más pastito alrededor, algunos con el piso de piedra, en otros teníamos playita de arena... muchas combinaciones, lo importante era que nos podíamos meter un rato al agua, tomar sol, disfrutar el verde, pasarla bien.

Los chicos disfrutando la pileta a fullEn un arroyo de por ahí

Uno de los días fuimos a visitar la Villa General Belgrano. Estuvo bueno porque visitamos el Museo Politemático Castillo Romano y paseamos un rato, pero el restaurant al qué íbamos siempre ya no es lo que era (la cerveza artesanal como aguada, la comida meh, la atención dejó que desear) y en general es una ciudad "demasiado turística" a la que no llegamos a disfrutar.

Un paseo que sí nos encantó de esos días fue el del Parque Recreativo de La Serranita, un lugar bárbaro con mil juegos y actividades. Hicimos minigolf, arquería, futpool, jugamos al tejo, carrera de bolitas, nos tiramos por un tobogán gigante, recorrimos un laberinto, hicimos actividades de treparse y equilibrio, adivinanzas y un montón de actividades más... estuvimos como seis horas ahí adentro (sin contar el almuerzo), súper recomendado para ir con la familia!

Practicando el mini-golfFelipe atacando un helado con ganas

Otra visita que disfrutamos fue a Nico y Jesi en La Quintana, donde pasamos una tarde bárbara charlando y tomando mate. Estuvo complicado llegar porque ya en viaje nos agarró una lluvia torrencial, y cuando llegamos a La Quintana los caminos estaban complicados... no sólo por el barro, sino también porque la lluvia había sido tanta que cada calle era un pequeño arroyo.

Encima tuve la suerte de presenciar (y casi participar!) en la instalación del primer prototipo funcional del LibreRouter en su antena, :D

Visitando La QuintanaEn el monumento a Mercedes Sosa

Las Sierras, lado Oeste

A mitad de las vacaciones cambiamos de lugar. Hicimos un pequeño viaje cruzando las sierras y nos fuimos hasta el segundo lugar que teníamos alquilado.

Era una casita mediana, súper equipada, en el medio de un inmenso terreno, cerca de una casa bien grande que era donde vivía la dueña. El paisaje era muy lindo, la verdad, todo muy cuidado, verde por doquier, hermoso.

Los peques, contemplando el paisajeFoto grupal en una de las construcciones de la Villa

Los días de la segunda fase estuvieron en general más frescos, lo que nos llevó a realizar menos actividades "acuáticas", pero no por eso aprovechamos menos las vacaciones: además de un par de veces en la pileta, y algunas en ríos/arroyos, "pancheamos" a full y paseamos algo.

A nivel de chapoteo, nos fuimos una vez a un Balneario en Paso de las Tropas, cerca de Nono, con la idea de almorzar, pasar la tarde, y luego apuntar para el Museo Rocsen, pero se nos fueron pasando las horas y después ya estábamos muy cansados, así que nos volvimos, dejamos el museo para la próxima. También encontramos una zona linda para aprovechar un arroyo cerca de donde nos hospedábamos (recorrimos un caminito con el auto hasta que no se pudo más, y luego un tramo a pie siguiendo el arroyo, hasta llegar a una linda zona para pasar la tarde). La verdad es que la primera vez nos quedamos en un punto con una pequeña cascadita, pero la segunda vez como cuando llegamos ya había gente, seguimos caminando un poco más y encontramos un lugar mejor :)

En un arroyito con unas cascadas hermosasPreparando el almuerzo al costado del agua

Con respecto a los paseos, fuimos varias veces a la Plaza de San Javier, unos kilómetros al norte. No sólo para las compras de supermercado y eso, sino porque había feria artesanal todos los días, entonces visitamos varias veces, e incluso caimos de casualidad en una obra de títeres que estuvo muy buena. Encima era una zona donde había varios lugares lindos para comer, e incluso un pequeño parque cervecero/heladería, al cual fuimos más de una vez :)

También hicimos varios kilómetros para el sur y visitamos la fábrica de aceite de oliva Sierra Pura. Nos encantó. Te reciben, te muestran los árboles contándote las diferencias entre los tipos de olivo que hay, luego te muestran las máquinas con las que producen, y te explican todo el proceso, contestándote las preguntas que se te ocurran. Como no hay turnos ni horarios, llegás, y al rato ya te hacen el paseo, sean 3, 7, o 15 personas. Al final, hay una degustación de todos los aceites que hacen (tres blends, tres varietales, y muchos saborizados), y obvio uno puede comprar ahí con algún descuento :)

Malena, disfrutando del aire libre

En fin. Vacaciones, paseo, descanso. Ahora de nuevo en la jungla, desde hace rato...

Marcelo Fernández: CORE Network Emulator

Investigando herramientas de simulación/emulación de redes con fines educativos, un amigo pasó esta página, bastante nutrida por cierto, con un listado de simuladores/emuladores de red, recomendando probar CORE.

C.O.R.E., acrónimo de Common Open Research Environment, fue un proyecto inicialmente de Boeing (sí, la de los aviones) y que ahora es sponsoreado por el Laboratorio de Investigación Naval de los Estados Unidos. Le dediqué un rato a revisar qué tal funcionaba, y aquí está lo que pude probar.

A priori, resulta que la última versión (4.8) está en los repos de Ubuntu 16.04, por lo que fue fácil la instalación [1]:

marcelo@marcelo-notebook:~$ apt-cache search core-network
 core-network - intuitive network emulator that interacts with real nets (metapackage)
 core-network-daemon - intuitive network emulator that interacts with real nets (daemon)
 core-network-gui - intuitive network emulator that interacts with real nets (GUI)

Se instalan esos paquetes y listo el pollo, las dependencias son básicas (TCL/TK y quagga):

marcelo@marcelo-notebook:~$ sudo apt install core-network core-network-gui
Leyendo lista de paquetes... Hecho
Creando árbol de dependencias
Leyendo la información de estado... Hecho
Se instalarán los siguientes paquetes adicionales:
 core-network-daemon libev4 libtcl8.5 libtk-img libtk8.5 quagga tcl8.5 tk8.5
Paquetes sugeridos:
 libtk-img-doc snmpd tcl-tclreadline
Se instalarán los siguientes paquetes NUEVOS:
 core-network core-network-daemon core-network-gui libev4 libtcl8.5 libtk-img libtk8.5 quagga tcl8.5 tk8.5
0 actualizados, 10 nuevos se instalarán, 0 para eliminar y 2 no actualizados.
Se necesita descargar 3.905 kB de archivos.
Se utilizarán 16,4 MB de espacio de disco adicional después de esta operación.
¿Desea continuar? [S/n]

Usarlo es tanto como ejecutar “core-gui” y empezar a armar el mapa de la red tal como se ve en el video de la página que citó Mauro:

Vista de Red - CORE

Vista de Red – CORE

El direccionamiento lo hace automáticamente (aunque es configurable, haciéndole doble click a cada nodo):

… y la configuración del ruteo se hace sola (ver más abajo cómo), por lo que luego de armar esa red sencilla, ambos hosts (“PC” y “Server”) se ven automáticamente.

Luego de armar la red, se le da al botón de “Play” y se ejecuta todo. Todos los nodos son Linux (nada de emulación routers Cisco ni nada como sucede con GNS3), y acá viene lo interesante:

  • Todos son containers (LXC) del mismo host de uno, pero sin estar en un chroot (?!?),
  • Es extremadamente rápido gracias a LXC, pero “raro” ya que todo corre en el mismo filesystem de la máquina de uno (puedo ir a mi home directamente desde cada nodo).
  • Dado que es un container, todos los kernels guest son los mismos del host.
  • ¡El software que se ejecuta es el mismo del host! Es decir, si digo que este nodo va a tener Apache (servicio “HTTP”), hay que instalar el paquete apache2 en el host, no en el guest. No hay imagen de máquina virtual ni nada por el estilo como pasa con otros emuladores.
  • El directorio que te abre al entrar a cada guest es/tmp/pycore.<PID>/<nombredelhost>.conf/
  • La configuración de los servicios/apps que va a usar en cada host la genera el entorno antes de darle “Play” en /tmp/pycore.<PID>/<nombredelhost>.conf/, por ejemplo:

Uno puede ir y editar los archivos en el directorio etc.apache2/ que generó el sistema una vez que se le dio ejecución, o puede hacerlo antes, tocando en el botón “Services” de la configuración del host:

Y luego en el ícono de llave inglesa:
Este es un ps desde el guest Server:

root@Server:/tmp/pycore.34211/Server.conf# ps faxu
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 9676 1708 ? S 12:20 0:00 /usr/sbin/vnoded -v -c /tmp/pycore.34211/Server -l /tmp/pycore.34211/Server.log -p /tmp/pycore.34211/Server.pid -C /tmp/pycore.34211/Server.conf
root 46 0.0 0.0 65508 3096 ? Ss 12:20 0:00 /usr/sbin/sshd -f /etc/ssh/sshd_config
root 52 0.0 0.0 56680 3772 ? Ss 12:20 0:00 /usr/sbin/apache2 -k start
www-data 53 0.0 0.0 411412 3504 ? Sl 12:20 0:00 \_ /usr/sbin/apache2 -k start
www-data 54 0.0 0.0 411412 3504 ? Sl 12:20 0:00 \_ /usr/sbin/apache2 -k start
root 110 0.0 0.0 23848 3968 pts/19 Ss 12:20 0:00 /bin/bash
root 236 0.0 0.0 39932 3316 pts/19 R+ 12:22 0:00 \_ ps faxu
root@Server:/tmp/pycore.34211/Server.conf#

Este es el running-config generado por core-network de un router (r1), entrando a Quagga con vtysh:Así que ahí vemos que define OSPF automáticamente:

Respecto a si se pueden guardar/cargar laboratorios completos, sí se puede, en el formato “imn” (ya que CORE es un fork de Imunes, y heredó su formato). Algo muy interesante es que se puede configurar el QoS de cada link, haciéndole doble click a cada línea (no lo probé):

Y que te grafica el ancho de banda en tiempo real de la red:

Por último, para hacer capturas de tráfico es bastante sencillo, probé dos opciones:

  1. Se corre en cada nodo que se desea un tcpdump guardando el tráfico, queda en el “home” de cada container guest (/tmp/pycore.<PID>/<nombredelhost>.conf/), y uno desde el host directamente ejecuta Wireshark y lo abre.
  2. Pude guardar todo el tráfico de la red en una única captura (esto, con netkit, no lo pudimos hacer de forma directa). Para ello, primero se arranca el entorno de simulación; esto hace que se creen dinámicamente los bridges a nivel de host y las interfaces virtuales de cada container, adjuntas a cada bridge (el virbr0 de la captura es de Virtualbox, ignórenlo):

Y bueno, para hacer la captura de toda la red al mismo tiempo, hay que decirle a Wireshark que capture en todos los bridges:

Filtré porque aparece tráfico OSPF todo el tiempo, lógicamente. Es cuestión de desactivarlo por defecto (configurando el servicio Quagga/Zebra). Un detalle de capturar así es que hay que ordenar por tiempo, porque el packet number queda desordenado. Pero ordenando por tiempo, lo seguí y aparentemente (hice un ping, nada más) el orden se mantiene (el “reloj” sería el host).

El manual está acá, parece que se pueden hacer muchísimas cosas más (entornos distribuidos, scripting automatizado en Python, etc.):
https://downloads.pf.itd.nrl.navy.mil/docs/core/core-html/index.html

Parece ser una muy buena herramienta para simular entornos de red, practicar y aprender sobre protocolos.

[1] Resulta que hace poco lo sacaron de Debian/Ubuntu, porque claro, el entorno gráfico se ejecuta como usuario normal, pero al abrir la consola de cualquier nodo que uno creó entra a la VM como root (y recuerden que no se está dentro de un chroot, con lo cual es root en el host con acceso al filesystem):

https://github.com/coreemu/core/issues/117

No lo solucionaron, entonces Debian los sacó, por ende no está en Debian Stretch. Igual maintainer del paquete tiene un repositorio personal para Debian/Ubuntu:

http://eriberto.pro.br/core/

Saludos

Marcos Dione: reprojecting-and-splitting-huge-datasets

Another aspect I've been looking into with respect to optimizing the rendering speed is data sources that are not in the target projection. Not being in the target projection forces Mapnik to reproject them on the fly, and this for each (meta)tile, whereas it would make more sense to have them already reprojected.

In my case I have 3 datasets, big ones, in EPSG:4258. The three datasets are elevation, hill and slope shade based on EEA's DEM files. The source tiles amount to almost 29GiB, and the elevation layer, being RGB, takes more than that. So I set off to try to reproject the things.

My first, more obvious approach was to reproject every 5x5°, 18000x18000px tile, then derive the data I need, but I started to get gaps between tiles. Notice that the original data is cleanly cut (5° x 3600"/° x 1px/" == 18000px), without any overlapping.

The next approach was to merge them all in a .vrt file, then reproject chunks of it with gdalwarp. What I wanted as output was the same 5x5° tiles, reprojected, but with an extra pixel, so they overlap. This last requirement was the problematic one. See, the final projection makes any square in the original projection a tall rectangle, stretching more and more towards the poles. The closest I could get was to use the -ts option, but that meant that I didn't get any control about how many extra pixels I got in the vertical/latitude direction. My OCD started thrashing :) In fact what happened was that I was not sure how GDAL would handle the possible partial pixel, whether rounding down (meaning excluding it), up (finishing it), or simply leaving the pixel with partial data and impacting the final rendering.

Even Rouault pointed to me that gdalwarp can do something fantastic: it can generate a .vrt file too with all the parameters needed for the reprojection, so reading from there was automatically reprojecting the original data. The resulting dataset is 288,000x325,220px (the original is 288,000x180,000px), so I'm definitely going to cut it down in small tiles. After consulting with a eight-ball, I decided to discard the idea of tiles with boundaries based on coordinates, which might not even make sense anymore, but settle for pixel based sizes, still with an extra pixel. The chosen size is 2**14+1 a.k.a. 16385. For this gdal_translate is perfect.

The final algorithm is like this:

gdalwarp -t_srs "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 \
    +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" \
    -r lanczos -tr 30.92208077590933 -30.92208077590933 \
    -of VRT EU-DEM.vrt EU-DEM-corrected.vrt

The values for the -tr option is the pixel size in meters, which is the unit declared in the SRS. Notice that as Mercator stretches towards the poles, this is the size at the origin of the projection; in this case, at 0° lat, 0° lon.

Then the reprojection (by reading from the reprojecting dataset) and cut, in a couple of loops:

tile_size=$((2**14)); \
for i in $(seq 0 17); do
    for j in $(seq 0 5); do
        for k in $(seq 0 3); do
            l=$((4*$j+$k));
            gdal_translate -co BIGTIFF=YES -co TILED=YES -co COMPRESS=LZMA \
                -co LZMA_PRESET=9 \
                -srcwin $(($tile_size*$i)) $(($tile_size*$l)) \
                    $(($tile_size+1)) $(($tile_size+1)) \
                -of GTiff EU-DEM-corrected.vrt \
                $(printf "%03dx%03d-corrected.tif" $i $l) &
        done;
        wait;
    done;
done

There's an extra loop to be able to launch 4 workers at the same time, because I have 4 cores. This doesn't occupy the 4 cores a 100% of the time (cores that already finished stay idle until the other finished), but it was getting akward to express in a Makefile, and this is run only once.

Before deriving the rest of the data there's an extra step: removing those generated tiles that actually have no data. I do a similar thing with empty sea tiles in the rendering process. Notice also that the original data is not tile complete for the covered region (79 tiles instead of the 160 they should be).


openstreetmap gis gdal

Marcos Dione: callable-choices-for-django-rest-framework

At work I'm writing an API using Django/DRF. Suddenly I had to write an application (just a few pages for calling a few endpoints), so I (ab)used DRF's Serializers to build them. One of the problems I faced while doing this was that DRF's ChoiceField accepts only a sequence with the values for the dropdown, unlike Django's, who also accepts callables. This means that once you gave it a set of values, it never ever changes, at least until you restart the application.

Unless, of course, you cheat. Or hack. Aren't those synonyms?

class UpdatedSequence:
    def __init__(self, update_func):
        self.update_func = update_func
        self.restart = True

        self.data = None
        self.index = 0


    def __iter__(self):
        # we're our own iterator
        return self


    def __next__(self):
        # if we're iterating from the beginning, call the function
        # and cache the result
        if self.restart:
            self.data = self.update_func()
            self.index = 0

        try:
            datum = self.data[self.index]
        except IndexError:
            # we reached the limit, start all over
            self.restart = True
            raise StopIteration
        else:
            self.index += 1
            self.restart = False

        return datum

This simple class tracks when you start iterating over it and calls the function you pass to obtain the data. Then it iterates over the result. When you reach the end, it marks it to start all over, so the next time you iterate over it, it will call the function again. The function you pass can be the all() method of a QuerySet or anything else that goes fetch data and returns an iterable.

In my case in particular, I also added a TimedCache so I don't read twice the db to fill two dropdown with the same info in the same form:

class TimedCache:
    '''A function wrapper that caches the result for a while.'''
    def __init__(self, f, timeout):
        self.f = f
        self.timeout = timeout
        self.last_executed = None
        self.cache = None
        self.__name__ = f.__name__ + ' (Cached %ds)' % timeout


    def __call__(self):
        now = time.monotonic()

        if self.cache is None or (now - self.last_executed) > self.timeout:
            self.cache = self.f()
            self.last_executed = now

        return self.cache

I hope this helps someone.


python django drf