Weblog

published Nov 03, 2021 , last modified Nov 04, 2021

Kilian Evang - Viasock: Automagically Serverize Your Scripts

published May 19, 2017

Kilian Evang talks about Viasock: Automagically Serverize Your Scripts

See the PyGrunn website for more info about this one-day Python conference in Groningen, The Netherlands.

Viasock's tagline: Automagically serverize your pipelines.

Pipelines. In the Parallel Meaning Bank, you input some text and it analyses each word. So each word goes through a pipeline.

The Unix philosophy (Doug McIlroy): - Write programs that do one thing and do it well. - Write programs to work together. - Write programs to handle text streams, because that is a universal interface.

A pipeline for us can be this:

$ cat data/01.txt | ./bin/tokenize -m models/tokenizer.model | ./bin/parse -m models/parser.model > out/01.parse

Get input, tokenize it, parse it, give output.

We might update our parsing module while the pipeline is running. We prefer not to redo the tokenize part then, especially if that has taken a long time.

We have a daemon that runs various make processes which update files, orchestrating which makefile is used for which document.

Problem: the tokenizer is meant to work on a big dataset, and needs ten seconds to start. If you run it on one sentence, it takes less than a second to process, but it still needs the ten second start. What to do?

We serverize it. Traditional approach would be to split the tokenizer in a server and client part. The server keeps running, only suffering the ten second startup penalty once. The clients quickly start up and contact the server and get an answer back quickly. Problem: you would need to split this up yourself. And you may need to do this for various tools.

So viasock was born. This is a client and server. The viasock server interacts with your normal, unchanged tool, the tokenizer in our case. The viasock server makes sure the tool is started once, and keeps it running. The viasock clients then talk to your tool via the viasock server.

There are limitations. Your tool must read standard input, process it, output it on standard output, and then repeat.

We want to automagically serverize tools without needing to keep track of changes in your tool, and making sure the viasock server is running before using the viasock client. So:

$ cat input1.txt | viasock run mytool -m mymodel > output1.txt
$ cat input2.txt | viasock run myothertool > output2.txt
$ cat input3.txt | viasock run mytool -m myothermodel > output3.txt

When needed, this starts a new instance of your tool if it is out of date. Any old instance is kept running, until we notice it does not get any new client connections for some time, and then we stop it.

Viasock calculates a SERVERID hash, based on your toolname, modification date, arguments, etcetera, and then uses or starts a server that listens on ./.viasock/sockets/$SERVERID.

If you frequently run a program with high startup overhead on small data, and you don't want to split it into server/client, then give viasock a try.

See the code at https://github.com/texttheater/viasock

See the slides.

Jaap Bresser - Beyond Role Based Auth: Discretionary Access Control with Postgres & SQLAlchemy

published May 19, 2017

Jaap Bresser goes beyond role based authorization: Discretionary Access Control with Postgres & SQLAlchemy

See the PyGrunn website for more info about this one-day Python conference in Groningen, The Netherlands.

I work at http://www.profileermij.nl and this talk is about what we did there. It is an online career platform.

Role based authentication: grant access control based on a role, instead of on a user. Generally it is quite simple and coarse grained: you can edit either all products or none. [I would call it authorization: what you are allowed to do instead of who you are.]

The core part of our website is the user profile, with hard skills (education, positions) and soft skills (personality, preferences). Sensitive data.

In the first version, we used role based authentication. Each customer has an own sub domain. Roles were: user, hr (human resources), admin.

Wanted was: allow users to share their profiles with others. So we looked to discretionary access control (DAC). The first mention I found was from the Department of Defense in 1985. Biggest thing: pass on permission to another subject. So you get authorization per object.

The Linux file system works like this, in a very basic way, where you can give access on a file to one user as well as one group or everyone.

Amazon Web services have resource based permissions and identity based permissions, and lots more options. Quite complex, needed for their wildly varying use cases.

For the profileermij case, we created an ACL (access control list) in a Postgres database. The app uses Flask. The ACL:

  • a principal uuid
  • actions: read, write, read_acl, write_acl
  • paths: dot separated, including wildcard and glob characters
  • a unique key for external reference

For implementing the ACL, we use the JSONB data type and the JSONB subset operator @>, a Gin index. You need Postgres version 9.4 or higher.

Sample query:

SELECT * FROM profile WHERE profile.acl @> {...};

In Python we use classes to wrap JSON, an SQLAlchemy TypeDecorator. We need to handle paths, and integratie the ACL in an existing application of framework. Processing a request would look like this:

  • incoming write request
  • validate against schema
  • convert to SQLAlchemy model
  • load ACL and check permissions
  • save SQLAlchemy object
  • return response

Take aways from our experience:

  • DAC meets our requirements
  • Designing a UX that is understandable for lots of people is hard
  • The complexity can be managed.
  • Don't apply it everywhere. You don't need it everywhere. For our profiles we needed it, for most other data not.

[Audience: Django REST framework has this.]

Marco Vellinga - Creating abstraction between consumer and datastore

published May 19, 2017

Marco Vellinga talks about Creating abstraction between consumer and datastore, at PyGrunn.

See the PyGrunn website for more info about this one-day Python conference in Groningen, The Netherlands.

Marco Vellinga is a programmer at Devhouse Spindle.

Default: web app connects to HTTP api that talks to your data store. And another web app talks to another HTTP api, and another, etcetera.

Better: let all apps talk to one data access layer. You need core logic, a contract on how apps can talk to you, validation, error handling.

Some cons:

  • It is quite difficult to find information about this on the internet.
  • It is a bit overkill for small projects.
  • It can take a long time to build before you get it right, at least longer than we expected.

In our solution, data needs to be (de)serializable in json. We are using marshmallow.

Filtering with and/or/not. We created FilterQL.

We wanted versioning of code paths and made a decorator for this. With that, you can call method.v1() and method.v2(). You can version classes or functions this way. We created versionary. You do want some deprecation policy here: having sixteen different versions of the same function seems a bad idea.

We have something for validation too, but we are working on that, it is too verbose currently.

In the end: is it worth building such an abstraction layer? The first day this went live, we found lots of mismatched data, so it helped us find errors in the data. If you can start from scratch, it helps.

Pizza's en portemonnees

published May 01, 2017

Column Klokgelui voor Overschiese krant.

Twee weken geleden was ik voor mijn werk in Italië. In Napels ging het snel mis: op een vol perron is mijn portemonnee gerold. Contant geld, bankpasjes, OV-chipkaart, identiteitskaart, kortingsbon voor een croissant, u kent het wel. Vervelend, en vooral een hoop gedoe en geregel. Gelukkig kon ik van een collega geld lenen, anders was het allemaal nog lastiger geworden.

Ik had meteen mijn bankpasjes geblokkeerd, en dat was op tijd. Mijn OV-chipkaart probeerde ik ook te blokkeren, omdat ik het saldo automatisch laat opwaarderen. Maar dan zou ik allerlei abonnementen die erop stonden kwijt zijn, die ik later met moeite op een nieuwe pas zou moeten zien te krijgen. Of ik kon direct een nieuwe bestellen, dan zou het allemaal goed gaan. Maar dan moest ik direct online betalen en dat ging niet, want daar had ik mijn bankpasje bij nodig. Tja.

Het automatisch opwaarderen kon ik online stopzetten. Probleem: deze opdracht moest ik bevestigen door met mijn OV-chipkaart naar een kaartautomaat te gaan. Zucht. Ik gaf het maar op: de kans dat de dief helemaal naar Nederland zou reizen om van mijn pas gebruik te maken, leek me klein.

Boos was ik eigenlijk niet. Teleurgesteld over een Napolitaanse dief, ja. Maar in het hotel werd ik goed geholpen: zij verzorgden de aangifte in het Italiaans bij de politie. Maar goed ook, want daar spraken ze geen Nederlands of Engels, en mijn kennis van het Italiaans gaat niet veel verder dan het eten. Al na twee dagen had ik een noodpaspoort via het consulaat, dus dat ging fijn snel. En de reisverzekering vergoedde gelukkig een deel van de kosten.

Het hoort niet, stelen. En ik zal er geen zielig, begrijpend verhaal bij verzinnen alsof de dief de opbrengst waarschijnlijk gebruikt heeft om zijn bloedjes van kinderen te eten te geven. Maar iets zegt me dat hij (zij?) er armer van is geworden dan ik.

Jezus zei: 'Als iemand je op de wang slaat, biedt hem dan ook de andere wang aan.' Als iemand je portemonnee rolt, wijs hem dan op het briefje van vijf dat eruit valt. Heb je vijand lief. Met enige tegenzin neem ik zijn raad toch maar aan. Het schijnt gezond te zijn.

P.S. Hierbij mijn felicitaties aan mede-columnist Kees van der Meer die benoemd is tot lid in de Orde van Oranje Nassau!

Het laatste woord

published Apr 03, 2017 , last modified Apr 30, 2017

Column Klokgelui voor Overschiese krant.

In het boekenweekgeschenk van Herman Koch noemde de hoofdpersoon een situatie die ik herkende. Misschien heeft u dat ook wel eens. Je hoort twee mensen discussiëren. Spreker 1 zegt iets en je denkt: dit klinkt redelijk. Spreker 2 zegt het tegenovergestelde en je denkt: logisch. Spreker 1 neemt weer het woord en je denkt: helemaal mee eens. Zo ben je het altijd eens met degene die als laatste het woord heeft.

In de politiek gebeurt dat vaak, zeker in verkiezingsdebatten. Wat de laatste spreker zegt, blijft het beste hangen. Een voorbeeld.

Spreker 1: 'De belastingen moeten omlaag. De gemiddelde Nederlander is er de afgelopen jaren alleen maar op achteruit gegaan, dat moet eens afgelopen zijn.' Klinkt logisch.

Spreker 2: 'We heffen geen belastingen voor de lol: daar doen we goede dingen mee. Als uw partij aan de macht komt, gaat de zorg achteruit want er is minder geld voor handen aan het bed. En de hardwerkende Nederlander staat langer in de file omdat u geen geld heeft om de snelwegen te verbeteren.' Goed punt.

Spreker 1: 'U behandelt de kiezer als een klein kind. U neemt hem aan de hand mee, want u weet zogenaamd wat het beste is. Daar trapt de kiezer niet in, die wil weer zelf over zijn eigen leven beslissen, in plaats van de hoge heren in Den Haag.' Daar heeft de spreker eigenlijk wel gelijk in.

Spreker 2: 'Ik weet inderdaad wat het beste is. Na de verkiezingen schaf ik dan ook de democratie af, word dictator voor het leven, en u gaat als eerste tegen de muur.'

En zo denk je steeds bij de laatste spreker dat hij of zij het beste punt heeft, tenzij het al te bont is. Maar goed, de verkiezingen zijn voorbij, de politici kunnen we even links of rechts laten liggen.

Ik geloof dat God het eerste woord heeft gehad. Hij sprak en er was licht. Op zijn woord vlogen sterren naar hun plaats, sprongen continenten naar voren, en verscheen de mens ten tonele. Nu houdt hij zich in en geeft mensen de gelegenheid om hun punt te maken, hun invulling aan de wereld te geven, te leven in een wereld met of zonder God. Maar ik geloof dat God het laatste woord gaat hebben. Ik denk dat ik het met hem eens ga zijn.