update with the new theme
2
Makefile
|
@ -1,4 +1,4 @@
|
||||||
build:
|
build:
|
||||||
pelican -s pelican.conf.py .
|
pelican -s pelican.conf.py content
|
||||||
upload: build
|
upload: build
|
||||||
rsync -e "ssh -p 22" -P -rvz --delete output/* alexis@172.19.2.119:/home/www/notmyidea.org/blog
|
rsync -e "ssh -p 22" -P -rvz --delete output/* alexis@172.19.2.119:/home/www/notmyidea.org/blog
|
||||||
|
|
190
content/dev/carto-forms-first-steps.rst
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
Carto Forms - First steps
|
||||||
|
#########################
|
||||||
|
|
||||||
|
:status: draft
|
||||||
|
|
||||||
|
For an introduction on carto forms, please see this blog post:
|
||||||
|
http://blog.notmyidea.org/carto-forms.html (and its variant in french if you
|
||||||
|
prefer: http://blog.notmyidea.org/carto-forms-fr.html)
|
||||||
|
|
||||||
|
So, let's not talk too much about what we want to do, and rather explain how we
|
||||||
|
will do it instead ;)
|
||||||
|
|
||||||
|
Writing this article turned out to dump my thinking while bootstraping the
|
||||||
|
project, so I'm really explaining how I'm getting from here to there ;)
|
||||||
|
|
||||||
|
First step: defining a way to describe forms
|
||||||
|
============================================
|
||||||
|
|
||||||
|
What we want is a generic way to describe forms. I'm not sure if such a thing
|
||||||
|
exist. And, because I'm on a train atm, let's suppose there isn't anything like
|
||||||
|
this already (which is probably a wrong assumption, but, let's stick with that
|
||||||
|
for now).
|
||||||
|
|
||||||
|
What do we want? A way to associate titles, descriptions to a field. We also
|
||||||
|
want to be able to describe what's *in* the field (the type of content), and if
|
||||||
|
it is a repeatable field or not. In the case of a selection, we might also want
|
||||||
|
to have a list of possibilities somewhere. Let's take a simple example:
|
||||||
|
|
||||||
|
Title: Ads spots
|
||||||
|
Description: Describe all the ads spots in Paris
|
||||||
|
Fields:
|
||||||
|
|
||||||
|
- location (geoloc/address/lat-long)
|
||||||
|
- size *the size of the ad* (choice list: small/medium/big/huge)
|
||||||
|
- light *is there light on it?* (boolean)
|
||||||
|
|
||||||
|
Okay, so what we have here is in the form: name *description* (type of field).
|
||||||
|
In some way, we need to separate the widget that will be displayed to the user
|
||||||
|
from the type of data. What we need here is the type of data, the widget thing
|
||||||
|
should be decided at a different layer. So, let's refine the "location" field
|
||||||
|
to "location (SIG point)".
|
||||||
|
|
||||||
|
Okay, we now know what we want to save. Yet, we need to define the format.
|
||||||
|
At this point, I'm wondering if I should use XML, YAML or JSON to describe this
|
||||||
|
data. To be able to choose, listing the potential consumers / providers of data
|
||||||
|
can help. The first consumer of this data will be a REST API, and the first
|
||||||
|
producer will be, probably javascript (or whatever techno is used on the
|
||||||
|
client). Of course, we can provide lots of format on the REST API and depend
|
||||||
|
on the "Content-Types" header to know how to talk to it, but well, do we really
|
||||||
|
want or need to do that? Let's assume no for now and stick with JSON, because
|
||||||
|
it's now easily validable and I can't think of a language without a lib for it
|
||||||
|
(apart COBOL, of course).
|
||||||
|
|
||||||
|
Hey-hi, JSON. How does our data look with you? Let's dump a python structure
|
||||||
|
and dump it with `json.dumps`::
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'title': 'Ads spots',
|
||||||
|
'description': 'All the ads spots in paris',
|
||||||
|
'fields': (
|
||||||
|
{'name': 'location', 'type': 'SIG point'},
|
||||||
|
{'name': 'size', 'type': 'choice', 'description': 'the size of the ad',
|
||||||
|
'choices': ('small', 'medium', 'big', 'huge')},
|
||||||
|
{'name': 'light', 'desciption': 'is there light on it?', 'type': 'bool'},
|
||||||
|
)}
|
||||||
|
import json
|
||||||
|
json.dumps(data)
|
||||||
|
|
||||||
|
… and the result is (ran with `python data.py | python -m json.tool`) …::
|
||||||
|
|
||||||
|
{
|
||||||
|
"title": "Ads spots"
|
||||||
|
"description": "All the ads spots in paris",
|
||||||
|
"fields": [
|
||||||
|
{
|
||||||
|
"name": "location",
|
||||||
|
"type": "SIG point"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"choices": [
|
||||||
|
"small",
|
||||||
|
"medium",
|
||||||
|
"big",
|
||||||
|
"huge"
|
||||||
|
],
|
||||||
|
"description": "the size of the ad",
|
||||||
|
"name": "size",
|
||||||
|
"type": "choice"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"desciption": "is there light on it?",
|
||||||
|
"name": "light",
|
||||||
|
"type": "bool"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
Validating the form definition
|
||||||
|
==============================
|
||||||
|
|
||||||
|
JSON is nice to us, JSON schema now exists and there are tools to work with it.
|
||||||
|
Quickly, it's the same kind of things than what's provided by XML Schema: you
|
||||||
|
create a schema, pass it some data and it's able to tell you if the data
|
||||||
|
complies with the schema. If not, it gives you a nice list of wrong fields.
|
||||||
|
|
||||||
|
The second option, in python, is a tool named colander, which approximately
|
||||||
|
does the same thing, but with its own syntax.
|
||||||
|
|
||||||
|
FIXME need to dig on json schema here and do an approx schema for this.
|
||||||
|
|
||||||
|
Creating the forms
|
||||||
|
==================
|
||||||
|
|
||||||
|
The next step is to actually create a form from this. Python, and django in
|
||||||
|
particular, have nice APIs to do that in python. However, I don't know how
|
||||||
|
they internally work, but you can pass to it some data provided by an HTTP POST
|
||||||
|
request and it will tell you if it validate or no.
|
||||||
|
|
||||||
|
The problem with django is that you're tied to it, and it's not possible (well,
|
||||||
|
as far as I know) to get only the validation bits out of it. On the other hand,
|
||||||
|
the form framework already comes with nice geolocation facilities. It could be
|
||||||
|
nice to have a tool able to parse the format we defined and to generate django
|
||||||
|
models out of it.
|
||||||
|
|
||||||
|
We need to be careful here: what I'm talking about is to generate code… Well,
|
||||||
|
there are two approches to do that: either we generate a python file and parse
|
||||||
|
it, or either we can read the json data and programatically create a form out
|
||||||
|
of it, at runtime. We might want to cache this at some point to avoid doing it
|
||||||
|
each time, but let's consider it's another problem we will tackle later.
|
||||||
|
|
||||||
|
So, django internals!
|
||||||
|
|
||||||
|
Let's loop on the fields provided by our format and generate the form. We will
|
||||||
|
care about how to store this / retrieve it later :)
|
||||||
|
|
||||||
|
Oh, but wait. I'm talking about forms but I should be talking about models!
|
||||||
|
Validation is one thing, but what we want to do is to describe the data we will
|
||||||
|
be handling. Forms will just be the user facing thing and what will to the
|
||||||
|
validation!
|
||||||
|
|
||||||
|
Django, no django? Let's think about this one more time. There is another
|
||||||
|
competitor on this field, because we are talking about storing information that
|
||||||
|
are changing all the time and to base validation on them: CouchDB! And there
|
||||||
|
also is GeoCouch, which brings interesting SIG features to Couch. And it's
|
||||||
|
talking JSON!
|
||||||
|
|
||||||
|
Creating a new form should be as easy as this::
|
||||||
|
|
||||||
|
$ curl -X POST localhost:5984/cartoforms/ -d "`python test.py`" -H "Content-Type: application/json"
|
||||||
|
{"ok":true,"id":"2d58ef2b02eae639b3f94e357a000d26","rev":"1-0462d0827e7cdad20b5703a923249220"}
|
||||||
|
|
||||||
|
Hmm, wait, this is cool but we got this hideous hash. Let's change this to a
|
||||||
|
PUT instead::
|
||||||
|
|
||||||
|
$ curl -X PUT localhost:5984/cartoforms/paris-ads -d "`python test.py`" -H "Content-Type: application/json"
|
||||||
|
{"ok":true,"id":"paris-ads","rev":"1-0462d0827e7cdad20b5703a923249220"}
|
||||||
|
|
||||||
|
Of course, we can already retrieve this with a GET::
|
||||||
|
|
||||||
|
curl -X GET localhost:5984/cartoforms/paris-ads -d "`python test.py`"
|
||||||
|
{"_id":"paris-ads","_rev":"1-0462d0827e7cdad20b5703a923249220","fields":[{"type":"SIG
|
||||||
|
point","name":"location"},{"choices":["small","medium","big","huge"],"type":"choice","name":"size","description":"the
|
||||||
|
size of the ad"},{"type":"bool","desciption":"is there light on
|
||||||
|
it?","name":"light"}],"description":"All the ads spots in
|
||||||
|
paris","title":"Ads spots"}
|
||||||
|
|
||||||
|
Validation? Yes, you're completely right: we need validation for this. Because
|
||||||
|
in this current state, anyone can just insert whatever data they want into this
|
||||||
|
system, which could become a problem at some point.
|
||||||
|
|
||||||
|
Let's say we don't care who is able to publish to the DB, until we know that
|
||||||
|
what's being posted complies with a certain format. And, guess what's cool?
|
||||||
|
CouchDB provides validators. Yeah, I agree, it's somewhat exhausting to realize
|
||||||
|
that we have all this for free, but, heh, that's open source, dude!
|
||||||
|
|
||||||
|
Adding validation!
|
||||||
|
==================
|
||||||
|
|
||||||
|
So, we described our format already, what we need to do is to create a couchdb
|
||||||
|
validator which is able to filter this.
|
||||||
|
|
||||||
|
Hmm, I don't remember how they are named (will find out in the couch
|
||||||
|
documentation), but if I remember correctly, you can hook up some javascript
|
||||||
|
functions to each POST / PUT, to check that the data inserted is correct, and
|
||||||
|
output appropriate error messages when it's not what you expected.
|
||||||
|
|
||||||
|
Yeah, this means writing javascript, which is cool because I wanted to re-learn
|
||||||
|
how to do javascript!
|
||||||
|
|
||||||
|
… train arrives to station, see you next :)
|
14
content/dev/python-functools-aliases.rst
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
Python, functools and aliases
|
||||||
|
#############################
|
||||||
|
|
||||||
|
:status: draft
|
||||||
|
|
||||||
|
I have been playing lately with python and functools to make method aliases. I
|
||||||
|
wanted to have something like this.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
class Baby(object):
|
||||||
|
|
||||||
|
def eat(self, thing):
|
||||||
|
self.intestine.digest(thing)
|
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
BIN
content/images/daybed.jpg
Normal file
After Width: | Height: | Size: 131 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 60 KiB |
Before Width: | Height: | Size: 57 KiB After Width: | Height: | Size: 57 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 127 KiB After Width: | Height: | Size: 127 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 119 KiB After Width: | Height: | Size: 119 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
58
content/mozilla/service-description.rst
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
API description using cornice and colander
|
||||||
|
##########################################
|
||||||
|
|
||||||
|
:status: draft
|
||||||
|
|
||||||
|
One of the goals we want to accomplish with Cornice is to describe the web
|
||||||
|
services in a nice and easy way, for the developer. This for different reasons.
|
||||||
|
|
||||||
|
Having web services described in some ways allows you do do interesting things,
|
||||||
|
such as automatically generating a documentation, or a client, for instance.
|
||||||
|
REST services are supposed to be discoverable, but in a lot of situations,
|
||||||
|
that's not the case, and it can be a pain to implement a client for them, even
|
||||||
|
if most of what is being done there is shared between a lot of web services.
|
||||||
|
|
||||||
|
In cornice, we alreadygenerate some documentation, but this one is incomplete in
|
||||||
|
different ways. For instance, it is currently not possible to get information
|
||||||
|
about the inputs you are waiting for, in the different locations (body,
|
||||||
|
headers and query string).
|
||||||
|
|
||||||
|
For instance, if you want to describe that a *POST* on `/foobar` needs the
|
||||||
|
*foo* and *bar* parameters, and that you eventually could add a *baz*
|
||||||
|
parameter, you can't, or you have to describe it manually in the documentation
|
||||||
|
of the web service.
|
||||||
|
|
||||||
|
Cornice, while not tied to `Colander`_, tries to make a good use of it when
|
||||||
|
possible. So it is possible to do validation of the incoming data (in different
|
||||||
|
locations) and, at the same time, documentation of the web service.
|
||||||
|
|
||||||
|
To do so, you have to use a particular `schema` keyword in the decorator. Here
|
||||||
|
is an example of definition
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from cornice import Service
|
||||||
|
from colander import MappingSchema, SchemaNode, String
|
||||||
|
|
||||||
|
foobar = Service(name="foobar", path="/foobar")
|
||||||
|
|
||||||
|
|
||||||
|
class Foobar(MappingSchema):
|
||||||
|
foo = SchemaNode(String(), location="body")
|
||||||
|
bar = SchemaNode(String(), location="headers")
|
||||||
|
baz = SchemaNode(String(), default=None)
|
||||||
|
|
||||||
|
|
||||||
|
@foobar.get(scheme=Foobar)
|
||||||
|
def foobar_get(request):
|
||||||
|
# do something here
|
||||||
|
|
||||||
|
.. _Colander: http://docs.pylonsproject.org/projects/colander/en/latest/
|
||||||
|
|
||||||
|
The output documentation currently looks like this:
|
||||||
|
|
||||||
|
.. image:: images/cornice-exampledoc-validation.png
|
||||||
|
|
||||||
|
The plans for the future are to be able to put direct curl calls in the
|
||||||
|
documentation to demonstrate how the service behaves for instance, and why not
|
||||||
|
creating a tiny python client able to consume the cornice APIs.
|
87
content/mozilla/token-server.rst
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
Mozilla - The sagrada token server
|
||||||
|
##################################
|
||||||
|
|
||||||
|
:date: 19-03-2012
|
||||||
|
:tags: sagrada, python, browserid
|
||||||
|
:status: draft
|
||||||
|
|
||||||
|
Since I started, back in december, we started a new project on the services
|
||||||
|
team, which aims to bring a central authentication point on our server side.
|
||||||
|
This had been motivated by the fact that we are switching our services
|
||||||
|
authentication mechanism from basic HTTP auth to browserid (this was basically
|
||||||
|
for sync in the first place, and now for AITC, a.k.a Market Place APIs).
|
||||||
|
|
||||||
|
- A Token Server ?
|
||||||
|
- Services architecture (server / nodes)
|
||||||
|
- MAC auth
|
||||||
|
- Crypto / Signing
|
||||||
|
- HKDF
|
||||||
|
- Signing the tokens
|
||||||
|
- Parsing browserid assertions
|
||||||
|
- Resources
|
||||||
|
|
||||||
|
A token server ?
|
||||||
|
================
|
||||||
|
|
||||||
|
So, we don't want to be tied to any authentication mean on our platform. The
|
||||||
|
best way to accomplish this is to chose one and to provide a way to map all the
|
||||||
|
potential authentication means to the chosen one.
|
||||||
|
|
||||||
|
In addition to trade a browserid assertion for another authentication token,
|
||||||
|
the mission of the token server is to retrieve the node allocation of a
|
||||||
|
particular user, and eventually assign it to a node.
|
||||||
|
|
||||||
|
To resume, we take any authentication scheme (browserid for now) and
|
||||||
|
trade it for another one we can use for all of our services. This has several
|
||||||
|
advantages:
|
||||||
|
|
||||||
|
* We don't need to check the browserid assertion at each request. This avoids
|
||||||
|
doing crypto at each request.
|
||||||
|
* As said, we are able to deal with different authentication schemes. If we
|
||||||
|
want to use openid, we just need to add support for it on one location
|
||||||
|
* The node allocation is done anyways (the user need to know wich node it is
|
||||||
|
assigned to) so it doesn't add an extra call for this.
|
||||||
|
|
||||||
|
Our architecture
|
||||||
|
================
|
||||||
|
|
||||||
|
I'm talking about nodes, users and services. Let's clarifiy a bit all this.
|
||||||
|
Because at the services team, we mostly care about being able to scale our
|
||||||
|
infrastructures without (too much) pain, we try to avoid SPOFs (Single Point Of
|
||||||
|
Failure) of any sort. For this purpose we expose at the authentication layer
|
||||||
|
information about the node that need to be retrieved by the clients.
|
||||||
|
|
||||||
|
What? clients? Okay, here is what the authentication looks like::
|
||||||
|
|
||||||
|
User-Agent Token Server Node
|
||||||
|
| | |
|
||||||
|
| <bid assertion> | |
|
||||||
|
|----------------------->| |
|
||||||
|
| | |
|
||||||
|
|<token + userid + node> | |
|
||||||
|
|<-----------------------| |
|
||||||
|
| | |
|
||||||
|
| <service-data + token> |
|
||||||
|
|----------------------------------------------->|
|
||||||
|
|
||||||
|
In HTTP terms, looks like this, the user agent (client) gives a browserid
|
||||||
|
assertion and receives back information about the service it should deal with
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
> HTTP POST http://token.services.mozilla.org/1.0/<app>/<app-version>
|
||||||
|
> Data: # some authentication information (browserid assertion in our case)
|
||||||
|
< Header: 200 OK
|
||||||
|
< Data: "{'id': token, 'key': secret, 'uid': uid, 'api_endpoint': api_endpoint}"
|
||||||
|
|
||||||
|
(This is an hand crafted request/response flow)
|
||||||
|
|
||||||
|
We don't bother about the signing and crypto details in here as it is explained
|
||||||
|
in a later section, but basically, we asked for a node, with a specific
|
||||||
|
browserid assertions and now we have an *api_endpoint* to send our requests
|
||||||
|
against, along with the token.
|
||||||
|
|
||||||
|
Crypto details
|
||||||
|
==============
|
||||||
|
|
||||||
|
All the flow is explained in our documentation, for the token server
|
83
content/mozilla/walint.rst
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
walint - tilt
|
||||||
|
#############
|
||||||
|
|
||||||
|
:status: draft
|
||||||
|
|
||||||
|
Things start to fold together. I still need some time to be up to
|
||||||
|
speed (new job / new city / new people), but the projects I'm working on are
|
||||||
|
pretty exciting and I like what I'm doing. We've been working with Tarek on a
|
||||||
|
tool about web services testing.
|
||||||
|
|
||||||
|
At Mozilla, we produce and consume web services. As an organisation defending
|
||||||
|
web standards, providing services that match these specifications is the least
|
||||||
|
we can do.
|
||||||
|
|
||||||
|
Web App Lint (WALint) is a simple tool to help you to test your web services
|
||||||
|
against the HTTP specification. The goal is to detect potential problems a
|
||||||
|
service could be subject to, and to provide a simple-to-configure tool to test
|
||||||
|
your WS against HTTP as speced. The long term goal is to be exhaustive on the
|
||||||
|
controllers we provide, but if you have special needs, you should be able to
|
||||||
|
define tests in a simple way.
|
||||||
|
|
||||||
|
As everything we do at Mozilla, the tool is an opensource project. Our goal is
|
||||||
|
to have something useful for web service consumers and providers. If you think
|
||||||
|
you can be of any help, don't hesitate to drop me an email or fork on github.
|
||||||
|
|
||||||
|
Testing the HTTP specification
|
||||||
|
==============================
|
||||||
|
|
||||||
|
A lot of web services are written on top of HTTP. The protocol is fully
|
||||||
|
described in a specification and introduce some really interesting stuff we
|
||||||
|
should care about when implementing our services. This tool wants to check this
|
||||||
|
up and provide a ways to ensure that you are defining your web services the
|
||||||
|
right way. It's not a replacement for manual service testing, thus: you still
|
||||||
|
have to test that your web service is doing what you think it does. WALint is
|
||||||
|
checking the stuff we almost forgot all of the time.
|
||||||
|
|
||||||
|
For instance, the HTTP specification specifies that if the client sends a
|
||||||
|
request with a Content-Type not handled by the server, it should answer with a
|
||||||
|
"406 Not Acceptable" and should return the list of accepted headers (so the
|
||||||
|
client is able to send again the request with the right accept header). We also
|
||||||
|
check that sending weird data (broken json objects or authentication headers)
|
||||||
|
does not break the tested service.
|
||||||
|
|
||||||
|
Obviously, we don't have all the scenarios in mind, and they aren't all
|
||||||
|
implemented. That's where being an open source project makes sense. You, as
|
||||||
|
service providers and consumers, know what are the kind of mistake you are used
|
||||||
|
to do / to deal with. It should make "tilt": fork the project and write some
|
||||||
|
lines checking the particular behavior that's disturbing you, everyone will
|
||||||
|
enjoy it. If you prefer, just open a ticket and we'll care about the
|
||||||
|
implementation.
|
||||||
|
|
||||||
|
The documentation defines a list of all the implemented controllers:
|
||||||
|
http://packages.python.org/walint/controllers.html
|
||||||
|
|
||||||
|
What does it looks like?
|
||||||
|
========================
|
||||||
|
|
||||||
|
Here is an example of a configuration file: you describe the paths and
|
||||||
|
signatures of your web services, the controllers you want to use and the test
|
||||||
|
scenarios you want to run, that's it, just run "walint config.cfg" and you're
|
||||||
|
good.
|
||||||
|
|
||||||
|
Here's a capture of the output of the command line invocation: you get all the
|
||||||
|
paths tested with the different listed methods, and if needed what's not
|
||||||
|
working. In the future, why not putting some documentation online with
|
||||||
|
information about how to fix common mistakes?
|
||||||
|
|
||||||
|
We also provide a wizard so it's possible to describe your web service in a
|
||||||
|
simple and easy way. Just invoke it with "walint --create config.cfg".
|
||||||
|
|
||||||
|
What's next ?
|
||||||
|
=============
|
||||||
|
|
||||||
|
We plan to do some fun stuff with WALint. Here are some thoughts:
|
||||||
|
|
||||||
|
* service discovery: just provide an API root URI and we'll try to discover
|
||||||
|
what's in there and how to generate configuration files
|
||||||
|
|
||||||
|
* unittest integration, so it's possible to have an unified way to describe web
|
||||||
|
services with existing tools. (heh, we can do Web Services CI the easy way!)
|
||||||
|
* integration with cornice description language and other web services description
|
||||||
|
languages (still to be defined)
|
||||||
|
* your ideas, so please fill issues and provide us feedback, it's useful!
|
84
content/mozilla/weekly-update.rst
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
Mozilla's weekly update #1
|
||||||
|
##########################
|
||||||
|
|
||||||
|
:date: 20-09-2012
|
||||||
|
:status: draft
|
||||||
|
|
||||||
|
My day-to-day work is changing a lot these days, as I'm working on different
|
||||||
|
tools and working across different teams. I thought it could be useful to have
|
||||||
|
a place to put updates weekly about what's going-on. This can be extra useful
|
||||||
|
for folks that are not on the same timezone I am (I'm looking at you,
|
||||||
|
California), so let's try this.
|
||||||
|
|
||||||
|
I'm not used to post regularly, but I will try to update the blog with an entry
|
||||||
|
each week, if there is something interesting to say.
|
||||||
|
|
||||||
|
Circus
|
||||||
|
======
|
||||||
|
|
||||||
|
As you may know, last week we had a sprint about Circus at PyconFR, we now have
|
||||||
|
a bunch of folks interested by the project now, and some activity on our irc
|
||||||
|
channel (#mozilla-circus on freenode).
|
||||||
|
|
||||||
|
I've written `a more comprehensive wrap-up about this sprint
|
||||||
|
<http://blog.notmyidea.org/circus-sprint-at-pyconfr.html>`_, so have a look at
|
||||||
|
it if you're interested!
|
||||||
|
|
||||||
|
Vaurien
|
||||||
|
=======
|
||||||
|
|
||||||
|
Vaurien is a TCP proxy which can be useful for our load-testing. its goal is to
|
||||||
|
sometimes let the traffic go trough, sometimes play a bit with it (add delays,
|
||||||
|
timeouts, close the socket etc) to check how the stack is behaving when under
|
||||||
|
pressure.
|
||||||
|
|
||||||
|
The code isn't used to test our services yet but we have something interesting
|
||||||
|
to show: http://github.com/mozilla-services/vaurien/
|
||||||
|
|
||||||
|
I will not explain the specifics here, I've tried to make `the README
|
||||||
|
<https://github.com/mozilla-services/vaurien#vaurien>`_ explicit enough.
|
||||||
|
|
||||||
|
Marteau
|
||||||
|
=======
|
||||||
|
|
||||||
|
`Marteau <https://github.com/mozilla-services/marteau/>`_ is the tool we're
|
||||||
|
using to throw load-test to our services, to check that they're able to handle
|
||||||
|
it. It's basically a frontend to Funkload. Tarek worked on adding real-time
|
||||||
|
feedback from the nodes (when in distributed mode, Funkload clients are
|
||||||
|
deployed on some nodes and send traffic to the service from there), and I am
|
||||||
|
working on making this available on the web interface. This means playing a bit
|
||||||
|
with web-sockets and javascript, yay.
|
||||||
|
|
||||||
|
Marketplace packaging
|
||||||
|
=====================
|
||||||
|
|
||||||
|
Currently, the application behind market place, `Zamboni
|
||||||
|
<https://github.com/mozilla/zamboni>`_ uses a non-standard mechanism to deal
|
||||||
|
with its dependencies. A `vendor` folder contains the packages themselves, in
|
||||||
|
the form of git submodules. This comes with some drawbacks such as the fact
|
||||||
|
that it's not easy to upgrade dependencies etc, and very long updates of the
|
||||||
|
repository, into other things.
|
||||||
|
|
||||||
|
We were also dependant on github to deploy Marketplace, which isn't reliable at
|
||||||
|
all, especially when you know that github was down last week, for instance. We
|
||||||
|
now have a local PyPI mirror at Mozilla, and we use it to avoid reaching the
|
||||||
|
internet for something else than our code.
|
||||||
|
|
||||||
|
This also means that we need to pull all the dependencies out of this `vendor`
|
||||||
|
folder, and rely on PyPI packages when they are up to date. Then we will be
|
||||||
|
able to directly use `pip` to deal with dependency management and packaging.
|
||||||
|
|
||||||
|
Splitting up the Marketplace
|
||||||
|
============================
|
||||||
|
|
||||||
|
Zamboni is currently one big django project. This led to something quite hard
|
||||||
|
to understand and hard to deal with., especially for newcomers. Also, it means
|
||||||
|
that all the aspects of the site are inter-connected and that you need to be
|
||||||
|
comfortable with the whole infrastructure of the project to add new features
|
||||||
|
/ fix bugs.
|
||||||
|
|
||||||
|
Splitting this big project into smaller chunks can allow to have something
|
||||||
|
easier to work on. We're trying to do that these days. More on this later :)
|
||||||
|
|
||||||
|
That's all for now, I'll try to keep you posted on all this, see you next week
|
||||||
|
:-)
|
|
@ -1,7 +1,6 @@
|
||||||
Cheese & code - Wrap-up
|
Cheese & code - Wrap-up
|
||||||
#######################
|
#######################
|
||||||
|
|
||||||
:status: draft
|
|
||||||
:date: 2012-10-22
|
:date: 2012-10-22
|
||||||
|
|
||||||
This week-end I hosted a *cheese & code* session in the country-side of Angers,
|
This week-end I hosted a *cheese & code* session in the country-side of Angers,
|
||||||
|
|
46
content/thoughts/focus.rst
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
Focusing on what's important
|
||||||
|
############################
|
||||||
|
|
||||||
|
:date: 16-03-2012
|
||||||
|
:tags: focus, time-management
|
||||||
|
:status: draft
|
||||||
|
|
||||||
|
I do have a problem with information.
|
||||||
|
|
||||||
|
Information overload.
|
||||||
|
|
||||||
|
This thing that makes me check my emails, irc, twitter, my feed reader etc.
|
||||||
|
This thing that makes me feel uncomfortable at the end of the day, because I
|
||||||
|
feel that I missed something. That I missed some good time, away from news and
|
||||||
|
agitation.
|
||||||
|
|
||||||
|
What do I need? I tried to change my tools, it helped a bit, Still, I'm not
|
||||||
|
focused like I would like to be. I've tried the pomodoro technique but… I'm not
|
||||||
|
yet convinced, mostly because this means me being interrupted every 20 minutes.
|
||||||
|
|
||||||
|
Maybe that's just me who needs some more persuasion over myself, but the best
|
||||||
|
way I found to work is to unplug the cable. Literally. At work, I'm using a
|
||||||
|
RJ45 cable to connect to the internet. When I want to work on something,
|
||||||
|
I just unplug this cable.
|
||||||
|
|
||||||
|
And that's amazing how you find yourself in the process to "check"
|
||||||
|
something on the web. Mails, irc… well, you got the idea.
|
||||||
|
|
||||||
|
Of course, that web isn't filled only with lolcats and twitter messages
|
||||||
|
(even if I would **love** to see a pie chart with the repartition of lolcats
|
||||||
|
VS the rest of the web's content), so sometimes you need some precious bit of
|
||||||
|
information that's there. Fair enough. plug the cable, do what you **need** to
|
||||||
|
do, and unplug. Alexis, unplug!
|
||||||
|
|
||||||
|
I'm feeling adventurous, so I'll try something new starting tomorrow, and I'll
|
||||||
|
report back in here my findings. Here's the challenge:
|
||||||
|
|
||||||
|
* **Check emails only twice a day**. Do not do it in the morning, before
|
||||||
|
working, to keep my mind clear. I would say at 2pm (after lunch) and at 8pm.
|
||||||
|
(This doesn't mean I will not send mails tho)
|
||||||
|
* Stay away from the internet during the morning. I'll not connect if I don't
|
||||||
|
need to.
|
||||||
|
|
||||||
|
I still need to find a way to be reachable during these off-line periods,
|
||||||
|
because that could be very painful for the folks on my team otherwise. (the
|
||||||
|
good thing is that my morning is their nights).
|
|
@ -1,87 +0,0 @@
|
||||||
@import url(http://fonts.googleapis.com/css?family=Rosario);
|
|
||||||
@import url("pygment.css");
|
|
||||||
@import url("typogrify.css");
|
|
||||||
|
|
||||||
body {
|
|
||||||
width: 800px;
|
|
||||||
margin: auto;
|
|
||||||
font-size: 1.3em;
|
|
||||||
background-color: #fffff0;
|
|
||||||
font-family: "Georgia", serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
a{
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
nav ul li {
|
|
||||||
float: right;
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
clear: both;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content h1, h2, h3, h4, h5, h6{
|
|
||||||
font-family: 'Rosario', arial, serif;
|
|
||||||
margin-left: -20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content h1{
|
|
||||||
font-size: 2.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content p{
|
|
||||||
font-size: 1.1em;
|
|
||||||
text-align: justify;
|
|
||||||
text-justify: newspaper;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content .date{
|
|
||||||
font-style: italic;
|
|
||||||
font-size: 0.7em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content h2{
|
|
||||||
font-size: 1.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content a{
|
|
||||||
padding: 2px;
|
|
||||||
color: #0F0F0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content a:hover{
|
|
||||||
background-color: #0F0F0F;
|
|
||||||
color: #eaeaea;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content .highlight pre{
|
|
||||||
padding: 15px;
|
|
||||||
background-color: black;
|
|
||||||
color: white;
|
|
||||||
overflow: scroll;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.content blockquote {
|
|
||||||
margin: 0px;
|
|
||||||
margin-right: 40px;
|
|
||||||
margin-left: 20px;
|
|
||||||
padding-left: 20px;
|
|
||||||
text-align: left;
|
|
||||||
border-left: 3px black solid;
|
|
||||||
letter-spacing: 2px;
|
|
||||||
font-style: italic;
|
|
||||||
text-align: justify;
|
|
||||||
}
|
|
||||||
|
|
||||||
.description {
|
|
||||||
margin-top: -15px;
|
|
||||||
font-style: italic;
|
|
||||||
}
|
|
|
@ -1,205 +0,0 @@
|
||||||
.hll {
|
|
||||||
background-color:#FFFFCC;
|
|
||||||
}
|
|
||||||
.c {
|
|
||||||
color:#408090;
|
|
||||||
font-style:italic;
|
|
||||||
}
|
|
||||||
.err {
|
|
||||||
border:1px solid #FF0000;
|
|
||||||
}
|
|
||||||
.k {
|
|
||||||
color:#007020;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.o {
|
|
||||||
color:#666666;
|
|
||||||
}
|
|
||||||
.cm {
|
|
||||||
color:#408090;
|
|
||||||
font-style:italic;
|
|
||||||
}
|
|
||||||
.cp {
|
|
||||||
color:#007020;
|
|
||||||
}
|
|
||||||
.c1 {
|
|
||||||
color:#408090;
|
|
||||||
font-style:italic;
|
|
||||||
}
|
|
||||||
.cs {
|
|
||||||
background-color:#FFF0F0;
|
|
||||||
color:#408090;
|
|
||||||
}
|
|
||||||
.gd {
|
|
||||||
color:#A00000;
|
|
||||||
}
|
|
||||||
.ge {
|
|
||||||
font-style:italic;
|
|
||||||
}
|
|
||||||
.gr {
|
|
||||||
color:#FF0000;
|
|
||||||
}
|
|
||||||
.gh {
|
|
||||||
color:#000080;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.gi {
|
|
||||||
color:#00A000;
|
|
||||||
}
|
|
||||||
.go {
|
|
||||||
color:#303030;
|
|
||||||
}
|
|
||||||
.gp {
|
|
||||||
color:#C65D09;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.gs {
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.gu {
|
|
||||||
color:#800080;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.gt {
|
|
||||||
color:#0040D0;
|
|
||||||
}
|
|
||||||
.kc {
|
|
||||||
color:#007020;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.kd {
|
|
||||||
color:#007020;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.kn {
|
|
||||||
color:#007020;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.kp {
|
|
||||||
color:#007020;
|
|
||||||
}
|
|
||||||
.kr {
|
|
||||||
color:#007020;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.kt {
|
|
||||||
color:#902000;
|
|
||||||
}
|
|
||||||
.m {
|
|
||||||
color:#208050;
|
|
||||||
}
|
|
||||||
.s {
|
|
||||||
color:#4070A0;
|
|
||||||
}
|
|
||||||
.na {
|
|
||||||
color:#4070A0;
|
|
||||||
}
|
|
||||||
.nb {
|
|
||||||
color:#007020;
|
|
||||||
}
|
|
||||||
.nc {
|
|
||||||
color:#0E84B5;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.no {
|
|
||||||
color:#60ADD5;
|
|
||||||
}
|
|
||||||
.nd {
|
|
||||||
color:#555555;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.ni {
|
|
||||||
color:#D55537;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.ne {
|
|
||||||
color:#007020;
|
|
||||||
}
|
|
||||||
.nf {
|
|
||||||
color:#06287E;
|
|
||||||
}
|
|
||||||
.nl {
|
|
||||||
color:#002070;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.nn {
|
|
||||||
color:#0E84B5;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.nt {
|
|
||||||
color:#062873;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.nv {
|
|
||||||
color:#BB60D5;
|
|
||||||
}
|
|
||||||
.ow {
|
|
||||||
color:#007020;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.w {
|
|
||||||
color:#BBBBBB;
|
|
||||||
}
|
|
||||||
.mf {
|
|
||||||
color:#208050;
|
|
||||||
}
|
|
||||||
.mh {
|
|
||||||
color:#208050;
|
|
||||||
}
|
|
||||||
.mi {
|
|
||||||
color:#208050;
|
|
||||||
}
|
|
||||||
.mo {
|
|
||||||
color:#208050;
|
|
||||||
}
|
|
||||||
.sb {
|
|
||||||
color:#4070A0;
|
|
||||||
}
|
|
||||||
.sc {
|
|
||||||
color:#4070A0;
|
|
||||||
}
|
|
||||||
.sd {
|
|
||||||
color:#4070A0;
|
|
||||||
font-style:italic;
|
|
||||||
}
|
|
||||||
.s2 {
|
|
||||||
color:#4070A0;
|
|
||||||
}
|
|
||||||
.se {
|
|
||||||
color:#4070A0;
|
|
||||||
font-weight:bold;
|
|
||||||
}
|
|
||||||
.sh {
|
|
||||||
color:#4070A0;
|
|
||||||
}
|
|
||||||
.si {
|
|
||||||
color:#70A0D0;
|
|
||||||
font-style:italic;
|
|
||||||
}
|
|
||||||
.sx {
|
|
||||||
color:#C65D09;
|
|
||||||
}
|
|
||||||
.sr {
|
|
||||||
color:#235388;
|
|
||||||
}
|
|
||||||
.s1 {
|
|
||||||
color:#4070A0;
|
|
||||||
}
|
|
||||||
.ss {
|
|
||||||
color:#517918;
|
|
||||||
}
|
|
||||||
.bp {
|
|
||||||
color:#007020;
|
|
||||||
}
|
|
||||||
.vc {
|
|
||||||
color:#BB60D5;
|
|
||||||
}
|
|
||||||
.vg {
|
|
||||||
color:#BB60D5;
|
|
||||||
}
|
|
||||||
.vi {
|
|
||||||
color:#BB60D5;
|
|
||||||
}
|
|
||||||
.il {
|
|
||||||
color:#208050;
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
.caps {font-size:.92em;}
|
|
||||||
.amp {color:#666; font-size:1.05em;font-family:"Warnock Pro", "Goudy Old Style","Palatino","Book Antiqua",serif; font-style:italic;}
|
|
||||||
.dquo {margin-left:-.38em;}
|
|
|
@ -1,30 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block title %}{{ article.title }}{% endblock title %}
|
|
||||||
{% block content %}
|
|
||||||
<h1>{{ article.title }}</h1>
|
|
||||||
<p class="date">{% if article.lang == "fr" %}Publié le{% else %}Published
|
|
||||||
on{% endif%} {{ article.locale_date }}.
|
|
||||||
{% if article.translations %}
|
|
||||||
{% if article.lang == "fr" %}Vous pouvez aussi lire cet article en {% else %}You can also read this article in {% endif %}
|
|
||||||
{% for tr in article.translations %}
|
|
||||||
<a href="{{ SITEURL }}/{{ tr.url}}">{{ tr.lang }}</a>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
{{ article.content }}
|
|
||||||
|
|
||||||
{% if DISQUS_SITENAME %}
|
|
||||||
<div class="comments">
|
|
||||||
<h2>Comments</h2>
|
|
||||||
<div id="disqus_thread"></div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
var disqus_identifier = "{{ article.url }}";
|
|
||||||
(function() {
|
|
||||||
var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
|
|
||||||
dsq.src = 'http://{{ DISQUS_SITENAME }}.disqus.com/embed.js';
|
|
||||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
|
@ -1,12 +0,0 @@
|
||||||
<!DOCTYPE HTML>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="content-type" content="text/html; charset=utf-8">
|
|
||||||
<link rel="stylesheet" href="{{ SITEURL }}/theme/css/{{ CSS_FILE }}" type="text/css" media="screen" charset="utf-8">
|
|
||||||
<link href="{{ SITEURL }}/{{ FEED }}" type="application/atom+xml" rel="alternate" title="{{ SITENAME }} ATOM Feed" />
|
|
||||||
<title>Alexis Métaireau</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="content clear">{% block content %}{% endblock %}</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -1,23 +0,0 @@
|
||||||
{% extends "base.html" %}
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<p>Hi and welcome in this web logs. I try here to talk about freedom, free
|
|
||||||
software, activism and education. And about anything I think would be
|
|
||||||
valuable to share.</p>
|
|
||||||
|
|
||||||
<p>Bienvenue sur ces carnets. J'essaye de parler ici de liberté,
|
|
||||||
de logiciel libre d'activisme et d'éducation. Et finalement d'un peu tout
|
|
||||||
ce qui me passe par la tête et que j'ai envie de partager.</p>
|
|
||||||
|
|
||||||
{% for article in articles %}
|
|
||||||
<h2><a href="{{ SITEURL }}/{{ article.url }}">{{ article.title }} ({{article.lang}})</a>
|
|
||||||
{% if article.translations %}
|
|
||||||
<small>(also in {% for article in article.translations %}<a href="{{ SITEURL }}/{{ article.url }}">{{ article.lang }}</a>{% endfor %})</small>
|
|
||||||
{% endif %}
|
|
||||||
<span class="date">{{ article.date.strftime('%B %Y')}}</span>
|
|
||||||
</h2>
|
|
||||||
{% if article.description %}
|
|
||||||
<p class="description">{{ article.description }}</p>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
{% endblock %}
|
|
|
@ -13,8 +13,8 @@ h1 {
|
||||||
|
|
||||||
.hentry {
|
.hentry {
|
||||||
border-left: 10px solid;
|
border-left: 10px solid;
|
||||||
border-color: rgba(200, 200, 200, .2);
|
border-color: rgba(200, 200, 200, .4);
|
||||||
color: rgba(200, 200, 200, .1);
|
color: rgba(200, 200, 200, .3);
|
||||||
padding: 40px;
|
padding: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,15 +32,15 @@ article .category {
|
||||||
}
|
}
|
||||||
|
|
||||||
.dev, .python {
|
.dev, .python {
|
||||||
border-color: rgba(150, 200, 150, .2);
|
border-color: rgba(150, 200, 150, .4);
|
||||||
color: rgba(150, 200, 150, .1);
|
color: rgba(150, 200, 150, .3);
|
||||||
}
|
}
|
||||||
.asso {
|
.asso {
|
||||||
border-color: rgba(200, 0, 0, .2);
|
border-color: rgba(200, 0, 0, .4);
|
||||||
color: rgba(200, 0, 0, .1);
|
color: rgba(200, 0, 0, .3);
|
||||||
}
|
}
|
||||||
|
|
||||||
.thoughts {
|
.thoughts {
|
||||||
border-color: rgba(100, 0, 100, .2);
|
border-color: rgba(100, 0, 100, .4);
|
||||||
color: rgba(100, 0, 100, .1);
|
color: rgba(100, 0, 100, .3);
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
/***** Global *****/
|
/***** Global *****/
|
||||||
/* Body */
|
/* Body */
|
||||||
body {
|
body {
|
||||||
background: #F5F4EF;
|
background: url('../images/background.jpg') fixed;
|
||||||
color: #000305;
|
color: #000305;
|
||||||
font-size: 87.5%; /* Base font size: 14px */
|
font-size: 87.5%; /* Base font size: 14px */
|
||||||
font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
font-family: 'Trebuchet MS', Trebuchet, 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
||||||
|
@ -165,7 +165,6 @@ img.left, figure.left {float: right; margin: 0 0 2em 2em;}
|
||||||
}
|
}
|
||||||
#banner h1 a:hover, #banner h1 a:active {
|
#banner h1 a:hover, #banner h1 a:active {
|
||||||
background: none;
|
background: none;
|
||||||
color: #C74350;
|
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
BIN
theme/static/images/background.jpg
Normal file
After Width: | Height: | Size: 1.4 MiB |