Planet Twisted

May 15, 2012

Duncan McGreggor

CERN, OpenStack Keep Resonance Cascades at Bay

Tim Bell preparing to get his
OpenStack on
As previously mentioned, there's a growing momentum around ops-oriented participation in the OpenStack community. DreamHost is deeply invested in DevOps, seeing how that's where we're going to be living in a few months! As Simon Anderson, CEO of DreamHost, recently said:
"When we're running a complex fabric of apps on over 5,000 servers across three data centers, we need a lean and nimble approach to software development and operational implementation. Without a DevOps approach, we wouldn't be able to push code into production as fast or as efficiently as we do, and our customers would not be happy! Today's developers demand up-to-the-hour security and performance updates to Internet infrastructure, so we aim to deliver just that with DevOps."
Though expressed in the context of our work, the import of DevOps that Simon's comment generally highlights is going to be increasingly important for nearly anyone running cloud services. 

In particular, I've been following the work of the intrepid folks at CERN. As such, this post is not about DreamHost; rather, it's a mad tale of OpenStack, DevOps, and averting alien invasion.

After countless long-distance phone conversations, a flight to Switzerland, and spending several days buying pints for a security guard in the know (referred to from now on as "Barney"), I've uncovered some profound truths -- Mulder-style -- and have confirmed that the impact of OpenStack at CERN is huge. 

Superficial examinations turn up the usual: CERN's planning slides, nice quotes, discussions of features and savings in time and money. For instance, in a recent email conversation with Tim "Gordon Freeman" Bell at CERN, I learned that 
"The CERN Agile Infrastructure project aims to develop CERN's computing resources and processes to support the expanding needs of LHC physicists and the CERN organisation."
I think these guys have been hanging out with Simon! But once you slip behind the scenes, peek at some of the whiteboards in unattended rooms, or rifle through notes lying about, you see that things are not what they appear. I've included a shot of Mr. OpenStack-at-CERN himself; this was my first clue.

Publicly, he's been working with other teams at CERN to:
  • modernise the data centre configuration tools and automating operations procedures
  • exploit wide scale use of virtualisation, improving flexibility and efficiency
  • enhance monitoring such that the usage of the infrastructure can be fully understood and tuned to maximise the resources available
But privately, it seems that he and his team have been doing much, much more. This was alluded to in a statement made by team member Jan van Eldik: "We expect the number of requests to insert non-standard specimens into the scanning beam of the Anti-Mass Spectrometer to significantly decrease, once automation is in place and everyone is using the standard infrastructure we are setting up."

That isn't to say there haven't been incidents...

Innocuously enough, the current toolchains are based around:
  • OpenStack as a single Infrastructure-as-a-Service providing physics experiment services, developer boxes, applications servers as well as the large batch farm
  • Puppet for configuration management
  • Scientific Linux CERN as the dominant operating system with sizeable chunk of Windows installs
But that second bullet caught my eye, and one of Barney's pub mates confirmed a rumor that we'd heard: the Puppet instances are actually trained headcrabs. The primary training tool? You guessed it, a crowbar. Barney said that the folks from Dell took inspiration from this and developed it further for their OpenStack deployment framework after an extended visit to CERN.

Although Barney hadn't seen any evidence of resonance cascades, there have been minor cross-dimensional disturbances as a result of some "cowboy" activity and folks not following DevOps best practices. This has been kept quiet for obvious reasons, but has led to a small pest problem in some of CERN's older tunnel complexes. As rouge elements are discovered, CERN has been educating transgressors aggressively. (Sometimes they go as far as sending employees to Xen training... or was it Xen training?)

One artist's conception of what success will
look like for OpenStack at CERN
Despite the minor hiccoughs along the way, CERN is aiming for success. (Given the lack of Combine and forced relocation programs, they're already doing better than Black Mesa's Anomalous Materials team.) Plans are in place for an initial pre-production service, OpenStack deployment this year. Following that, they will be moving towards 300,000 virtual machines on 15,000 hosts spread across two data centres by 2015.

The OpenStack community is supporting them in their efforts with fantastic new features, high-quality discussions on the mail lists, and real-time interaction on the IRC channels. In an act of reciprocity and community spirit, operators at CERN have volunteered to contribute back to the OpenStack community with regard to operations best practices, reference architecture documentation, and support on the operators' mail list.

To see how other institutions were taking this news, I spent several days waiting on hold. In particular, Aperture Science could not be reached for comment. However, Ops team member Belmiro Rodrigues Moreira did say that there's an audio file being circulated at CERN of Cave Johnson threatening to "burn down OpenStack" ... with lemons. Given Aperture Science's failure record with time machine development, it's generally assumed to be a prank audio reconstruction. CloudStack developers are considered to be the prime suspects, seeing how much time they have on their hands while waiting for ant to finish compiling the latest Java contributions.

When asked what advice he could give to shops deploying OpenStack, Tim said simply: "Remember, the cake is a lie. Don't get distracted and don't stop. Just keep hacking."

Alyx, explaining to her dad why she loves DreamHost
Couldn't have said it better myself.

In closing, and interestingly enough, one of DreamHost's employees has an uncle who works at the Black Mesa Research Facility. Though his teleportation research team was too busy for an extended interview, his daughter did mention that she is a DreamHost customer and can't wait to use OpenStack while interning at CERN next summer. After all, that's what she uses to auto-scale her WordPress blog (she's in our private beta program).

It's a small world.

And, thanks to Tim and the rest at CERN, a safer one, too.


by Duncan McGreggor (noreply@blogger.com) at May 15, 2012 07:05 PM

May 14, 2012

Duncan McGreggor

Twisted SSH: Rendering a Log-in Banner/MOTD in Conch

A few weeks ago, I pinged my peeps on #twisted asking why the banner for a custom SSH server wasn't rendering properly. After some digging around and some inconsistent results (well, consistently bad results for me), we weren't able to resolve anything, and I had to set the problem aside.

The Symptom
The first thing I had tried was subclassing Manhole from twisted.conch.manhole, overriding (and up-calling) connectionMade, writing the banner to the terminal upon successful connection. This didn't work, so I then tried overriding initializeScreen by subclassing twisted.conch.recvline.RecvLine. Also a no-go. And by "didn't work" here's what I mean:

In both Linux (Ubuntu 12.04 LTS, gnome-terminal) and Mac (OS X 10.6.8, Terminal.app), after a successful login to the Twisted SSH server, the following sequence would occur:
  1. an interactive Python prompt was rendered, e.g., ":>>"
  2. the banner was getting written to the terminal, and
  3. the terminal screen refreshed with the prompt at the top
This all happened so quickly, that I usually never even saw #1 and #2. Just the second ":>>" prompt from #3. Only by scrolling up the terminal buffer would I see that the banner had actually been rendered. Even though I was doing my terminal.write after connectionMade and initializeScreen, it didn't seem to matter.

Discovery!
Some time last week, I put together example Twisted plugins showing what the problem was, and the circumstances under which a banner simply didn't get rendered. The idea was that I would provide some bare-bones test cases that demonstrated where the problem was occurring, post them to IRC or the Twisted mail list, and we could finally get it resolved. 'Cause, ya know, I really want my banners ...

While tweaking the second Twisted plugin example, I finally poked my head into the right method and discovered the issue. Here's what's happening:

  • twisted.conch.recvline.RecvLine.connectionMade calls t.c.recvline.RecvLine.initializeScreen
  • t.c.recvline.RecvLine.initializeScreen does a terminal.reset, writes the prompt, and then switches to insert mode. But this is a red herring. Since something after initializeScreen is causing the problem, we really need to be asking "who's calling connectionMade?"
  • t.c.manhole_ssh.TerminalSession.openShell is what kicks it off when it calls the transportFactory (which is really TerminalSessionTransport)
  • openShell takes one parameter, proto -- this is very important :-)
  • openShell instantiates TerminalSessionTransport
  • TerminalSessionTransport does one more thing after calling the makeConnection method on an insults.ServerProtocol instance (the one I had tried overriding without success), and as such, this is the prime suspect for what was preventing the banner from being properly displayed: it calls  chainedProtocol.terminalProtocol.terminalSize
  • chainedProtocol is an insults.ServerProtocol instance, and its terminalProtocol attribute is set when ServerProtocol.connectionMade is called.
  • A quick check reveals that terminalProtocol is none other than the proto parameter passed to openShell.

But what is proto? Some debugging (and the fact that of the three terminalSize methods in all of twisted, only one is an actual implementation) reveals that proto is a RecvLine instance. Reading that method uncovers the culprit in our whodunnit:  the first thing the method does is call terminal.eraseDisplay.

Bingo! (And this is what I was referring to above when I said "poked my head" ...)

Since this was called after all of my attempts to display a banner using both connectionMade and initializeScreen, there's no way my efforts would have succeeded.

Here's What You Do
How do you get around this? Easy! Subclass :-)

The class  TerminalSessionTransport in t.c.manhole_ssh is the bad boy that calls terminalSize (which calls eraseDisplay). It's the last thing that TerminalSessionTransport does in its __init__, so if we subclass it, and render our banner at the end of our __init__, we should be golden. And we are :-)

You can see an example of this here.

Not sure if this sort of thing is better off in projects that make use of Twisted, or if it would be worth while to add this feature to Twisted itself. Time (and blog comments) will tell.

Epilogue
As is evident from the screenshot above (and the link), this feature is part of the DreamSSH project. There are a handful of other nifty features/shortcuts that I have implemented in DreamSSH (plus some cool ones that are coming) and I'm using them in projects that need a custom SSH server. I released the first version of DreamSSH last night, and there's a pretty clear README on the github project page.

One of the niftier things I did last night in preparation for the release was to dig into Twisted plugins and override some behaviour there. In order to make sure that the conveniences I had provided for devs with the Makefile were available for anyone who had DreamSSH installed, I added subcommands... but if the service was already running, these would fail. How to work around that (and other Twisted plugin tidbits) are probably best saved for another post, though :-)


by Duncan McGreggor (noreply@blogger.com) at May 14, 2012 03:39 PM

May 13, 2012

Duncan McGreggor

DreamJob!

Do you love architecting new and creative software? Are you a hacker with mad Python skills and a freak for distributed services? Would you like to see your work offered to a huge, Internet audience? Do you want to help build a community around your work? Do you always vote for the underdog?

I've got just the position for you!

DreamHost is hiring for a new, senior engineering opening on the Cloud Team in the Development Group, and if you can not only easily imagine the extraordinary skill sets necessary to do what we're planning, but also have that skill set, we have got to talk.

We're a small company that's pure heart-and-soul with a culture that simply can't be beat. We've been hiring some incredible talent from the Python and open source communities, and need to finish building out this visionary team that will be taking DreamHost into the next 10 years of online services and software. This role is particularly focused on shaping that future -- from a technical as well as strategic perspective.

You can email me or ping me on IRC (oubiwann on freenode.net). We can chat, and if you've got what it takes, we will set up an interview with the rest of the Cloud Team.

I look forward to hearing from you :-)

Update: There's be a lot of interest in this position from folks with a wide range of professional experiences, so I've shared the job description here. This should give you a good sense of what we're looking for from your past, and the sorts of things we'd be expecting in your future :-)

by Duncan McGreggor (noreply@blogger.com) at May 13, 2012 01:54 AM

May 09, 2012

Jp Calderone

Commercial support contracts for Twisted

Last week I posted a survey to gauge interest in commercial Twisted support contracts to the Twisted mailing list:

http://twistedmatrix.com/pipermail/twisted-python/2012-May/025537.html

If you think this might be applicable to your interests and you didn't see the initial posting or haven't had a chance to respond yet, please take a minute or two to fill it out (it's very short, no essay questions at all). Thanks!

by Jean-Paul Calderone (noreply@blogger.com) at May 09, 2012 03:57 PM

May 07, 2012

Itamar Shtull-Trauring

The founding story of scientific management

If you've heard of Frederick Taylor, you've probably heard the foundational story of scientific management: Taylor observes workers moving pig iron, applies his superior intellectual capabilities to redesign the process, and by motivating one of the workers with pay achieves a four-fold increase in productivity. As it turns out, however, this story was "erroneous", or perhaps "more fiction than fact". The authors of these two papers are overpolite; in practice Taylor's experiment was a failure, and he lied about the results so successfully that it took 75 years before anyone called him on it. More here if you don't want to chase down JSTOR access (your public library will likely have a subscription you can use).

by Itamar Turner-Trauring (noreply@blogger.com) at May 07, 2012 11:19 AM

May 02, 2012

Moshe Zadka

Reasonable Units for Distances

Given the theory of relativity, C (the speed of light) has absolute meaning. Since speed is distance/time, this means that we have a standard way of converting time into distance. Instead of measuring time and distance in different units, we should be using the same units.

Hence, a second (in meters), would be 299,792,458. Of course, that’s quite a distance — so instead, let’s do the standard thing and use prefixes to scale it down to useful numbers.

1 nanosecond =~ .3m =~ 0.984 feet (if you need less than 3% accuracy, a nanosecond is a foot)
1 microsecond =~ 0.3km =~ 0.1875 miles

I’m roughly .495 nanoseconds tall. My wife is around .525 nanoseconds. I have to drive about 160 microseconds to get to work — for most of it, the legal speed limit is around 340 micros. (Note — speed has no more units, but it does have scale — the legal speed limit is 340*10e-6). Anyone else up to the task of starting to measure distance in nano- and micro- seconds in real life?


by moshez at May 02, 2012 04:25 PM

April 25, 2012

Duncan McGreggor

New Life: The OpenStack DevOps Community

Last week's OpenStack Design Summit and Conference were pretty fantastic events. Lots of great technical discussions, some good initial planning on large tasks, incredible numbers of conversations -- all of high quality! Looking back, though, I'd have to say that the high point of the event for me was what turned into the DevOps community brainstorm session (etherpad link) at the Design Summit (all etherpads are here).

The session was approved with the title of "OpenStack and Operations: Getting Real" with a major goal of deciding whether we needed to create a new top-level project for DevOps. So it was really "New DevOps Team?" However, all that changed once we got started, and there was some amazing feedback and enthusiasm in that room. By the end of it, we were all pretty pumped up and ready to jump in with all our hands and feet!

The highest-level summary for me was this: The DevOps folks in the OpenStack community really need a point to rally around. Someplace they can not only talk to each other, share stories, get advice, etc., but also where they can have their voices heard by the predominantly developer-oriented OpenStack community. Jay Pipes suggested that a new section be added to the weekly IRC team leader meetings, and as Nova Ops subteam lead (teams list), I volunteered to collect top issues from the DevOps (sub-)community and give these some air-time in the meetings.

Some other highlights from the session:

  • trystack.org needs volunteer admins -- a great opportunity for improving the dev <-> ops interface
  • CERN is deeply invested in DevOps, and wants to share data and possibly help with defining reference architectures
  • The same goes for the University of Melbourne!
  • There was a good corporate presences in the session too, rallying around a new and improved DevOps community: HP, Yahoo, AT&T, Canonical, Rackspace, DreamHost, and more (sorry if I forgot you!) 

There is a tremendous amount of information that we collected, but in written form (etherpads) as well as conversations during last week's event. As this is collected, we'll be reaching out to folks via the operators mail list, blog posts, tweets, and Google+ messages. Be sure to do the same! If you've got concerns, bring them up on the mail list, we'll get some bugs filed and blueprints put together, and come up with plans for addressing these.

Thanks again, everyone!


by Duncan McGreggor (noreply@blogger.com) at April 25, 2012 07:47 PM

April 21, 2012

Jp Calderone

GNOME Bug Reports

Almost ten years after jwz coined "CADT", they're still at it. Way to keep the dream alive, guys.

by Jean-Paul Calderone (noreply@blogger.com) at April 21, 2012 02:51 PM

April 13, 2012

Glyph Lefkowitz

We'll Always Have Cambridge

Half-way through 2012, I will be leaving the east coast.

There are a great many things I despair of leaving behind; family, friends, the most excellent Boston Python Meetup, participating in the sometimes incendiary, sometimes hilarious Cambridge, Massachusetts / Cambridge, England rap war.

However, I'm not writing today in order to wax lyrical about the area, or to extoll the virtues of my new home, but hopefully, to prevent a missed opportunity.  I know there are at least a few really cool people in Massachusetts who read this blog, and who read my tweets, that I either haven't seen in quite a while or have never actually met in person.

So if grabbing a coffee with me is an interesting idea to you, please drop me a line within the next month. I would love to hear your story about how PHP ruined your summer, or how Twisted changed your life, or how you once pwned a vending machine with nothing but a malformed JPEG.

I'm sure I'll visit the area from time to time, so this isn't quite your last chance, but it just won't be the same, you know?

If I follow you, you can DM me on Twitter of course, but my email address isn't hard to figure out either.  If you glance up towards the top of your browser window right now, you're practically looking at it.

by glyph (noreply@blogger.com) at April 13, 2012 09:32 PM

April 12, 2012

Duncan McGreggor

New Domain Name for the Blog

JP's wonderful blog sub-domain (and clever joke sub-domain) got me to thinking about what to do for a blog name again. Especially in the event that I ever leave blogger. For a year I tried using tau.tologo.us, but I think that was far too obscure a play on words. I gave up for a few years after that, and just stuck with the original username.blogspot.com setup.

After revisiting the possibilities again, looking at everything from rephrasing Maxwell's equations as sub-domains to using a play on Hindi words (I almost went with blog.bija.li, doing the electric thing as well as going for the esoteric seed syllable/mantra reference). Also too obscure.

After too many hours on Google Translate (trying something out, getting it translated, back-translating it; that often provides humorous -- if not enlightening -- results), I managed to stumble across one I really liked. Immediately, in fact: cogitat.io.

How is it that this hasn't been taken? I was dumb-founded. And delighted :-) Check out the possible translations of the Latin goodness:
  • thought
  • cogitation
  • thinking
  • considering
  • deliberating
  • reflection
  • meditation
  • reflexion
  • thought
  • design
  • plan
  • reasoning power

Splitting words at the tld, we get the aptly wonderful cogitat i/o: "he thinks I/O." As a programmer who specializes in side effects (don't most of us?), I'm surrounded by I/O. I view it as software's analog to the ever-important physics (and life) concept of "cause and effect." Needless to say, I do love the tld.

With the domain all set up, I was off to Blogspot... only to find that Google doesn't let you use "naked" domains as your blog name.

*sigh*

So then it was back to the drawing board (Google Translate). Fortunately, after just a few minutes of playing around, technicae popped up, and I thought this might be it. technicae cogitat io can almost be translated as "meditating on technology" or "the design of technology."

But there's more: I saw that if io was typed with a capital I, it would render the translation as "John." Which has led to the ultimate, most profound, inner-most secret essence of this blog:
Technicae cogitat Io.
Videre Io currunt.
Currere, Io! Currere!
Probably not something something Cicero would have recognized, nor even something parsable in Vulgar Latin. Most of you have probably already got it, though. Regardless, here it is in naked English:
"John thinks about technology.
See John run.
Run, John! Run!"

by Duncan McGreggor (noreply@blogger.com) at April 12, 2012 04:45 AM

April 05, 2012

Duncan McGreggor

Recent Stackiness

Meetup

Tomorrow is OpenStack Atlanta's second event (the first being a HackIn).  Ken Pepple is going to be talking about deploying OpenStack, something he should feel very comfortable doing, given his book as well as Internap's latest announcement :-)

There's more info about tomorrow's event at the Meetup page.

OpenStack Design Summit

In a couple weeks, a bunch of us from DreamHost are going to be heading to the OpenStack Summit and Conference in San Francisco. There's a lot of buzz about it both inside the company, in the offices of our fellow OpenStack collaborators, and in the wider open source community. With Citrix's recent announcement, Internap's deployment, Eucalyptus' approval by Amazon, there's plenty of Cloud Drama to go around. Fortunately, the focus of the Summit and Conference is on the important positives: how to improve an extraordinary piece of software and disseminating expertise. Can't wait!

GitHub Love

Last but not least, the Dev team at DreamHost has been using Github in conjunction with Launchpad in a manner similar to how the OpenStack project does it. The increased interest in open source software in our offices is starting to make its way out to our customers, and we've got a new web presence that is the first step in supporting this new direction. We're cooking up a bunch more stuff, so be sure to check in on our repos from time to time :-)


by Duncan McGreggor (noreply@blogger.com) at April 05, 2012 03:14 PM

April 01, 2012

Thomas Vander Stichele

Evolution backup recovery

I pretty much never drink and hack, and last Friday’s evening is a good reason why. I was having a rare beer and managed to spill part of it on my keyboard and desk. So I turned the keyboard around, started cleaning it as fast as I could, forgetting to actually unplug it. I called it a night because nothing good was going to come from that night anymore.

And on Saturday morning I noticed that my INBOX was gone. Hm, is it really gone? Yep, gone from my laptop too. Crap, must have deleted it on the server by accident while cleaning my keyboard…

And because my NAS is a little full lately, I haven’t been as diligent with backups as I normally have been. Hm, and the modest cache on my N900 isn’t very useful either…

Luckily, evolution on my work machine was shut down for some reason, so yay, it has a reasonably fresh cache of my INBOX!

Except that it’s not all that straightforward to actually get this cache back into Evolution. Just copying its contents to an existing or new folder doesn’t do anything. The files themselves are split up versions of the actual email, assumingly because the evo guys thought it would be faster to search header and body by splitting them off from the attachments and saving them separately, inventing their own caching format. Which is fine, but makes it impossible to actually restore a backup with…

After lots of Googling, I stumbled upon this tool that did the trick for me. A lot of hours wasted over a bunch of emails… But what would happen if I really lost my IMAP server mail ? Run this script by hand on all the folders ? Shudder…

by Thomas at April 01, 2012 02:36 PM

March 31, 2012

Twisted Matrix Laboratories

Google Summer of Code and Outreach Program for Women

Twisted is participating in Google's Summer of Code this year. If you're a student interested in working on Twisted as part of a paid internship, please visit our Google SoC page. We use best practices like in-depth code reviews and full coverage unit tests, so this is a great way to improve your technical skills whether you're a beginner or an expert programmer.

In addition, Twisted and its non-profit home the Software Freedom Conservancy have partnered with the GNOME Outreach Program for Women to fund an internship for one woman to spend the summer participating in and contributing to Twisted, while being mentored by Jessica McKellar. Jessica is a long-time Twisted contributor as well as a software engineer and an organiser, among other things, of the Boston Python Workshops for women.

Unlike Google's program, the outreach program is not restricted to students; if you qualify, we do encourage you to apply to both. This internship is appropriate for any level of open source experience. If you have worked on an open source project before, great! If not, we'll help you learn the development and communication tools we use as part of the internship. Some Python experience is a prerequisite, and a small initial contribution to Twisted is a part of applying (if this sounds intimidating, don't worry, we'll help you pick a task to complete and you'll have lots of support as you work through submitting your first patch.) Please check out the full project description and apply today!

by Itamar Turner-Trauring (noreply@blogger.com) at March 31, 2012 01:59 PM

March 30, 2012

David Reid

Deferreds Are A Dataflow Abstraction

This was originally concieved as a response to A Conversation with Guido about Callbacks over at Duncan McGreggor’s blog.

First, a jQuery-ish example of using some callbacks:

def handleResponse(resp):
    def handleParsed(xmlObj):
          firstStyle = xmlObj.xpath('//link[rel="stylesheet"]')[0]

        def handleAnotherResponse(anotherResp):
              print anotherResp

        getPage(firstStyle['href'], handleAnotherResponse)

    asyncParser(resp.body, onComplete)

getPage("http://example.com", handleResponse)

Now this is an absurd example of callback soup. Or is it? I’ve read a lot of JavaScript, and it isn’t really uncommon to see multiple levels of calls which take a callback. The JavaScript actually usually looks cleaner and is easier to read than our contrived Python because JavaScript has multi-statement anonymous functions that can be used to inline the callback definition into the function call. (That feature has other readability side-effects though, such as the pattern of defining a single argument anonymous function to invoke a single, single argument function.)

Now, when you write callbacks like this, it’s no wonder people tend to dislike them. Especially when contrasted with the more straightforward non-callback example.

resp = getPage('http://example.com')
xmlObj = parser(resp.body)
firstStyle = xmlObj.xpath('…')[0]
print getPage(firstStyle['href'])

4 lines of code vs 8 lines of code (11 including almost mandatory blank lines.) Is it any wonder that Guido prefers this approach? No, absolutely not. That first example is an absolutely terrible but perfectly normal piece of callback using code. Let’s enumerate some of the ways in which it is bad.

  1. Everything is out of order.
  2. Excessive indentation. Flat is better than nested, but close is better than far, so nested wins.
  3. The desire for locality causes function definitions to be scattered among statements.
  4. You’re defining a lot of non-reusable, non-testable functions.

I’m sure you’ve come up with plenty more of complaints (including non-PEP8 camelCase names) but these are the 4 big points I’d like to discuss further.

Order matters.

Most of us read left to right and top to bottom. Even if your primary language doesn’t read left to right and top to bottom your primary programming language almost certainly does. When we make todo lists we give them an order, items at the top are more important. Shopping lists are sometimes ordered starting with vegetables and moving towards more time fragile things like ice cream, because that’s the way the stores are laid out. Computer programs are written line by line in the order we want instructions executed, because that is how computers work.

Order matters. On first encounters with code order matters a lot.

Locality is the topic of both issues 2 & 3. And it can best be summed up as, related things should be close. It’s the most basic element of organization for everything from kitchens to code.

Anytime you’re reading anything you’ll find yourself glancing back to reread a few lines, or sentences, or even words as soon as you’ve encountered something that you don’t understand or doesn’t quite make sense. The further you have to look the longer it’s going to take to get your answer.

Reduce, Reuse, Retest.

We write functions to enhance the readability, and testability of our code. We reduce the size of large functions by breaking them up into higher level discrete steps and creating functions to encapsulate those actions. We reuse common code by creating more functions. We retest, ok well retest doesn’t make much sense, but we increase testability by concentrating functionality into smaller more well defined units.

You would never inline all the socket calls necessary to make an HTTP request. Maintainable software is built out of well defined reusable and testable abstractions, and there is no reason that callbacks should not also be reusable and testable as much as possible.

There is a better way.

I’ll admit, I have a love/hate relationship with callbacks. I view them as a necessary evil to do event-driven programming. There is of course a better way to think about callbacks and you may have already guessed it. Deferreds and Dataflow programming. A lot of people use deferreds for the first time much the same way they use plain callbacks.

d = getPage(…)
def handleResponse(resp):
    def handleParsed(xmlObj):
        firstStyle = xmlObj.xpath(…)
        def handleOtherResponse(otherResponse):
              print otherResponse

        d3 = getPage(firstStyle['href'])
        d3.addCallback(handleOtherResponse)

    d2 = asyncParser(resp.body)
    d2.addCallback(handleParsed)

d.addCallback(handleResponse)

Now, this example, though still contrived is not unrealistic, it is in fact perfectly functional and probably exists in more than a few Twisted using code bases. Of course it’s terrible for all the same reasons our plain callback example was terrible.

So clearly it is not the better way. So what is?

Deferreds as a dataflow abstraction.

A Visual Explanation of Deferreds

Here you have a acyclic directed graph of data through the callback chain. The individual operations being performed is less important than the flow of information through the structure. An event causes a result to be available, it is put into the deferred and moves along the directed graph through the callback chain until an error is encountered. Then we move to the errback chain will proceed until the error has been handled at which point we can go back to the callback chain, or until we run out of errbacks.

The result from one operation flows directly into the next.

getPage(getFirstStyle(parse(getPage("http://example.com")))

The above is a dataflow program. Our imperative example from earlier is not, because the grouping of operations is a side effect of style, any number of operations could be interspersed which may or may not have side effects that influence future operations.

d = getPage("http://example.com")
d.addCallback(parse)
d.addCallback(getFirstStyle)
d.addCallback(getPage)
d.addCallback(printResult)

Now, everything is order, related operations are close, and the structure of higher level operation is broken up into discrete and independently testable units.

By this point I hope I have made it obvious about why “thinking in Deferreds” is better than “thinking in callbacks” but if I have not imagine this example from a fictional streaming API and maybe you’ll understand why “thinking in dataflows” is a good thing.

urls.flowTo(getPage)
    .flowTo(parse)
    .flowTo(getFirstStyle)
    .flowTo(getPage)
    .flowTo(stdout)

urls.put("http://example.com")
urls.put("http://google.com")

Now we have encapsulated not only how we handle one result, but rather a potentially infinite number of events. Now we have the potential for building some realtime distributed systems.

That is all.

Go read about Storm and Orc

March 30, 2012 07:00 AM

March 29, 2012

Thomas Vander Stichele

git bash prompt

I’ve been having fun recently on a new project where I put myself through all sorts of pain by nesting git submodules into team submodules into platform submodules and so on. The goal here is to be able to tag a root repository and thus identify exact commit hashes of all the submodules to any level. This was an idea Andoni had when he was working on livetranscoding in response to a request of mine where I want to be able to use a single ‘tag’ to identify a complete deployment.

That’s been working better than I expected, and I even hacked git-submodule-tools so that I can do git rlog and get a recursive git log between two root version tags, and get a list of every commit between the master and all submodules. That’s pretty neat for writing out release notes.

However, the way I embedded submodules causes a bit of pain when going back and forth. One of my hackers once gave me a PS1 bash prompt that includes info of which git branch you’re on in your shell prompt. So today I decided to extend that a little, and I now have this:

(b:release-0.2.x d:deploy-pro-2012-03-29) [thomas@otto platform]$ ls
Makefile platform puppet RELEASE-0.2.1
(b:release-0.2.x d:deploy-pro-2012-03-29) [thomas@otto platform]$ cd puppet/pro/
(s:puppet/pro b:release-0.2.x d:v0.2.1) [thomas@otto pro]$

This is showing me submodule name, branch, and description of the current commit.

If you want this for your prompting fun too, here’s the github repo

In the near future, simple portknocking for fun and profit with bash!

by Thomas at March 29, 2012 07:39 PM

March 28, 2012

David Reid

Klein A Twisted.web Microframework

What is Klein?

klein is a micro-framework built out of widely used components that aims to be production ready out of the box.

Inspired by frameworks such as flask and bottle it features:

  1. A minimalist API.
  2. A fast, event-driven, production-ready web server.
  3. Complete support for a wide range of asynchronous client APIs.

It’s routing is provided by werkzeug and it’s webserver & event-loop by Twisted.

An Example

from klein import run, route

@route('/')
def hello(request):
    return 'Hello, world!'

run('localhost', 8080)

This is the most simple example possible. It’s actually simpler than the first bottle example. This is the example you want to use in the “how fast can I serve a hard coded static string” benchmark you post to Hacker News

This post will not contain one of those benchmarks. Lets break it down.

from klein import run, route

run and route are the most basic APIs and it should be pretty clear what they are for. In this example we’ve imported the top-level functions which actually operate on a global instance of a the class klein.Klein.

This class may be used directly to facilitate a more flask-like usage. For example:

from klein import Klein

app = Klein()

@app.route('/')
def hello(request):
    return 'Hello, world!'

app.run('localhost', 8080)

Next we have the actual handler definition:

@route('/')
def hello(request):
    return 'Hello, world!'

The route decorator is built on top of Werkzeug and passes all unknown arguments directly to werkzeug.routing.Rule.

You may have noticed that unlike both flask and bottle handler functions in klein take an explicit request argument, which is an IRequest provider. This is primarily because “Explicit is better than Implicit”, but also because anything else would greatly complicate the implementation.

At this point we have our feet firmly planted in the world of Twisted. Though our example does not do anything asynchronous, or Twisted specific the full power of Twisted is available to us. You may return a str, unicode, twisted.web.template.Element, or twisted.web.resource.IResource, and klein will handle all of them for you. You may of course also return a twisted.internet.defer.Deferred which fires with any of the above as it’s result and we will handle that as well. The README of course has examples covering the full range of return values.

Finally we are ready to run the server.

run('localhost', 8080)

This starts up a twisted web server listening on port 8080 and only accessible to localhost. You can listen any specific IP address, or ‘0.0.0.0’ for all IP addresses. As a bonus logging to stdout is set up for you.

Work in Progress

klein is of course not complete, as no software is ever complete. It does however have a comprehensive test suite and builds on Twisted’s own heroicly extensive tests. We have lots of ideas about how to improve it and don’t plan to stop developing it. It is not currently used in production anywhere but it’s only a matter of time.

If you try it give us feedback in #twisted.web on freenode. And of course fork it on github.

March 28, 2012 07:00 AM

March 27, 2012

Thomas Vander Stichele

Puppet pains

The jury is still out on puppet as far as I’m concerned.

On the one hand, of course I relish that feeling of ultimate power you are promised over all those machines… I appreciate the incremental improvements it lets you make, and have it give you the feeling that anything will be possible.

But sometimes, it is just so painful to deal with. Agent runs are incredibly slow. It really shouldn’t take over a minute for a simple configuration with four machines. Also, does it really need to be eating 400 MB of RAM while it does so ? And when running with the default included web server (is that webrick ?), I have to restart my puppetmaster for every single run because there is this one multiple definition that I can’t figure out that simply goes away when you restart, but comes back after an agent run:
err: Could not retrieve catalog from remote server: Error 400 on SERVER: Duplicate definition: Class[Firewall::Drop] is already defined; cannot redefine at /etc/puppet/environments/testing/modules/manifests/firewall/drop.pp:19 on node esp

And sometimes it’s just painfully silly. I just spent two hours trying to figure out why my production machine couldn’t complete its puppet run.

All it was telling me was
Could not evaluate: 'test' is not executable

After a lot of googling, I stumbled on this ticket. And indeed, I had a file called ‘test’ in my /root directory.

I couldn’t agree with the reporter more:

I find it incredibly un-pragmatic to have policies fail to run whenever someone creates a file in root which matches the name of an executable I am running.

by Thomas at March 27, 2012 01:53 PM

March 26, 2012

Duncan McGreggor

Some Thoughts on the Mobile Device Interface

Smartphones: Yesterday's News


As some of you know, I started 2010 by working in a new position at Canonical: Ubuntu Project Manager. I've been having an absolute blast; working my butt off has never been more fun, challenging, or interesting. I'm finding that nearly every side-interest I've had in the past several years is coming to the forefront in my project management work.

There were all sorts of adjustments I needed to make before PM'ing again, and one of those was catching up on communication technology. I now live by email, calendars, IRC, Skype, and phone conversations. Gone are the days of going heads-down into some code for a week or two. I need to stay connected, 100% of the time. I needed to get a smartphone.

What I really wanted was a Nokia N900. Sadly, T-Mobile's not offering one, so I got an Android phone with a physical keyboard instead: a new G1. Yeah, out of date, but considering that I was still using a Razr, the G1 is cutting-edge ;-)

I gotta tell you, this little phone has changed my life. The craziest thing is not the apps, the Market, the features, etc.; it's the touchscreen that has made me a believer.

You Can Touch This


I can't believe how radically the touchscreen phone has changed my computing habits and preferences. When I sit down at my laptop or desktop to do something quickly, I don't want use the keyboard or mouse. I want to point, swipe, and tweak with my fingers. When I'm on the phone, my brain has my speaking and text-processing faculties tied up. To easily multitask while talking, I need to be able to use a different part of my brain: that part involved in motor control.

I like using the touchscreen so much that I will often use my G1 for tasks that are better suited for my laptop, merely because of the joy I get from using the interface.

Touch, tap, drag, push, swipe. I love it. Can't get enough of it.

The best thing of all? This is really silly: I love the virtual desktops and being able to navigate between them with a swipe. Whose idea was this? That designer or engineer needs to be promoted! I have never experienced a more intuitive way of switching virtual desktops. I didn't even know how much this was important to me until I used the G1. I want this for my laptop!

Having such a positive bias towards tactile technology, you can imagine my joy when I saw this Ubuntu blueprint. And then when I was asked to work with Bryce and Andy on the PM portion of multi-touch support, I was quite delighted. This will give application developers and device engineers what they need in order to start creating new exciting stuff for the Ubuntu world. You will be able to have an iPad-like experience on your Linux devices (that have the proper hardware).

The thing is, as much fun as tactile interfaces are, I want way more now. I've been given a taste... now I want the banquet.

An Interface for the Future


So the iPad has been getting lots of press. It's bigger than a phone, I like that: I could replace my pen-and-paper medium-sized Moleskine with one. The thing I like the best though? Yeah, you guessed it: the interface. Curling pages and apps that have been re-worked specifically for the new format/size. I love it when a device lets me use it in a way that is natural and intuitive, and provides visual (or other sensory) feedback on my use.

Apple has made, in my opinion, a good and interesting product. But certainly not a revolutionary one. It's a natural progression from what folks are already doing with smartphones and netbooks.
So let's talk about revolutionary :-)

Imagine you've got a crazy new shirt, one whose fibers convert your movements to electrical current and can power your devices. Perhaps it comes with a "battery net" for literally flexible power storage. Now imagine that some clever sod has equipped your shirt with sockets for micro-SD cards (or something similar). If you've read my "After the Cloud" posts, then you probably know where I'm going with this :-)

Now add some embedded micro-controllers, and bluetooth, a smart phone with cloud-controller software, and you've got a personal S3 with potentially terabytes of light-weight, wearable storage. And your phone controls the nodes, redundancy, failover, etc. Maybe your phone runs Ubuntu and you're pushing backups of your personal cloud onto your U1 account.

But how do we interface with all this great storage? Here comes the banquet I mentioned :-)

I want to be able to reach "into" my phone, grab an icon (application, file, contact, whatever) and put it where I want. But I mean really put it: I can pick up some data off my desktop, and throw it over my shoulder or at my feet. With appropriate sensing equipemnt on the power shirt's sleeves, my arms and hands are now the perfect "mice."

In fact, there's no more virtual desktop (that's old skool). One of the new primary functions of your mobile device is to peer "into" the halo of data that surrounds you now. You can either spin your virtual storage space around you like an inverted, 3D lazy susan, our you can physically move your phone around, like a diving mask peering into the water.

Closing Thoughts


The more data I have, the more I feel that I live in it. The problem is that our current tech forces us into tiny sardine cans and we have to consume our data with the equivalent of a single chop-stick. If I'm going to live in my data, I want to have the best possible experience of immersion that I can. I want an interface that can handle my future.

I could go on and on... I love this sort of thing. The important thing to know now is that the community is working on the building blocks for our technological future. The first steps are being made in open source software that will allow us to take giant, insanely cool steps in the not-to-distant future.


by Duncan McGreggor (noreply@blogger.com) at March 26, 2012 02:36 PM

The Future of Personal Data: A Followup

The Next Step

A few years ago, I wrote a post about the Future of Personal Data as a result of all the ultra large-scale systems reading and exploration I was doing. Google was foremost in my mind when writing that, but Apple has since come into the spotlight here as well.

Recently, Matt Zimmerman has decided to leave Canonical and join forces with Singly, an exciting startup company focused on secure user data storage and the socialization of (and development around) that data. In this blog post, the following core values were given about the software underlying Singly:
  • I own my personal data
  • I want my data to be useful to me
  • I make the decisions to protect or share my
I would like to see the following added:
  • I make the decisions on how my data is used
  • If my data is sold, I should get a return for this
This is not petulance speaking :-) This comes from a historical perspective on social and economic fairness. Witness the changes in individual rights and personal finance since the industrial revolution...

Fair Market Value

There are probably many solvent entities out there who would claim users are already getting a return for the use of their data: free email and office docs from Google, free cloud services from Apple, etc. But I would imagine that there are massive margins being made on user data, and services (as valuable as they may be) are a paltry return for such a gold mine. I cannot help but be reminded of the selling price of Manhattan Island or Alaska (in 2011 values, the Lenape Indians got around $29.61/square mile; the Russians got about $150.77/square mile).

Money makes a good point, but personal data (and this post) isn't about the almighty coin. This is about clearly defining who owns what and ensuring that those who don't want to be taken advantage of, aren't. This is about identifying exploitation, and building something better and longer-lasting in its place.

Who's Going to Pay for What?

In David Pakman's "Disruption" blog post about Singly, he makes the following comment:
"I cannot see consumers getting into the business of selling their data to marketers so they can see personalized advertising. Instead, I believe marketers will be encouraged to offer value to us in exchange for access to our data."
I have to agree with him... but I can only offer a qualified agreement. True, I find it hard to believe that users will be selling their data directly to marketers. From the user-side, the pain of inconvenience would not likely be worth the payoff; at the marketer end, individual data is useless, and munging an in-house-built collection would incur a lot of overhead not part of their core business.

However, users' data stored in lockers, updated regularly, pre-processed, has enormous value in the market. Right now, Apple and Google are making eye-crossing amounts of money from data just like this. Again, I would imagine that this data is only really valuable in large quantities and for interesting, identifiable demographics

If users provide their data, but in exchange only get a "nicer app" or a "useful utility" I'm going to cry "foul!" (unless someone can show me the actual numbers involved and unequivocally prove that fair exchange is occurring).

You Say Disruption, I Say Revolution

Instead, if a service such as Singly, were to offer a co-op style dividend payment system to all of its users, that would seem to be much more fair. Not only that, it would be the beginning of a market revolution. This is not to say that co-ops are some perfect economic model, but rather that the data we, as users, generate is of immense value. The more that Singly has, the greater potential for revenue. The more buzz that builds around Singly users generating revenue from their data, the more users they get. With mass-adoption, a new sub-economy is born.

Perhaps a better model than co-op is that of a mutual fund investment firm. Each Singly user has a portfolio of data. Depending upon each user's preferences, any or all of that data could be used by Singly to generate revenue. Some groups of users will generate more than others, and users in these groups would get greater returns.

Whichever analogy you prefer, with a little exploration it seems fairly clear that opportunities for a large payout are present. For instance, I like to imagine a world where entities like Apple and Google can't harvest user data, but must go through brokers whom users have given their permission to sell their data for the most profit. I also imagine there's a lot of lawmaking that would have to take place... and even more lobbying.

Even with that, Google and Apple would still make money hand over fist (or they'd become brokers themselves) -- enough to continue providing free services. Yet at the same time, users would be in control of their data; they'd be financing (or financially augmenting) their data-consumption lives with said data.

With the right press coverage, Singly could find themselves not only swamped with a massively growing user base, but at the very center of a new economy. With the right level of negotiation and coordination, businesses could buy into this new paradigm without losing their shirts in the disruption.

A Plea

In summary, I applaud the goals and vision of Singly. I, for one, would deeply appreciate writing applications against their data locker (to any Facebook or any of its dubious applications), where a user's rights are clear and protected. That being said, Sinlgy would have my eternal allegiance if they also took up the cause of rights for user data in the market place; if they helped transform the current nascent data economy into a world economy capable of achieving as-yet unimagined financial heights.

And if not Singly, my loyalty would be given to whomever did do this.


by Duncan McGreggor (noreply@blogger.com) at March 26, 2012 02:31 PM

Physical Beings with Digital Lives

2001A Space Odyssey
There's a lot that one could say about that title. In fact, it could be the title of a high-volume collaborative blog... That aside, here's the context for this post: books. Books and Reality. And data.
This post got so long that I now need to add a list of sections here, just to make it more accessible. My apologies :-/

Mini Table of Contents
  • Books
  • Books in the Sky
  • Yeah, I Know: Go Social
  • Human Data History
  • Reality Merges
  • Conclusion
Books


I have tons of books. Actual, physical books. Walls of them. Some I use all the time (reference). Some I read once a year (good books that support multiple reads). Others I've only read once, perhaps as far back as high school (when I started collecting). My bookshelves are like a random associative memory array: reading each title or the act of pulling one from the shelf brings back a flood of memories, relived experiences, sometimes actual sense perceptions. It's a powerfully visceral activity.

But that's just my books. When I'm at friends' homes or offices, I cannot keep my eyes off their bookshelves. It's an irresistible compulsion. I linger and browse, often past any semblance of socially acceptable time limits. My conversational replies experience a rapid exponential die-off -- in duration, gaps, and semantic value -- culminating in grunts and finally silence. (My favorite offices to visit so far? friend mathematicians/maths professors!)

Books in the Sky


Oddly, I love books in digital format. I never really got hung up on the bit about not having the paper entity in my hands (though I have turned a digital book reader over, expecting the next page... though that was deep in the plot of a Greg Egan novel!). Traveling as much as I do, I'm in heaven with ebooks. I feel like Superman, carrying around a library with me everywhere I go.

But when I passed a bookshelf the other day on my way out the door and fell under the spell of a book-memory flashback, I realized what was going away as I transitioned to virtual books. And the painful question arose: How am I going to nurture future layers of book-mulch and text-humus with this new æthereal, cloud-bound library I'm building?

How can I share with others, my stacks of books? How will I browse friends' books in their offices, asking about author X and title Y? How will we borrow from each other? What can be done to add this and related missing richness back into our lives once we adopt the virtual versions?

Light-emitting walls that can display titles from your Amazon account? Virtual over-lays visible with wearable/immersive computing accessories? Whatever we end up with, a gimmick isn't going to cut it. It will need to reflect the same depth of history that stacks of physical books have come to represent to us and the collective human psyche since we first started gathers works of the written word.

Yeah, I Know: Go Social


I'm hung up on books here, I admit it. But the same goes equally well for much of what we experience in online social media as well. Everyone's trying to make a buck on people chatting, playing games, reading, etc. Business as usual.

But the problem is that everyone coming up with their own little solution, one piece at a time. Google, Facebook, LinkedIn, Last.fm, etc. "We socialize X." Wow. Good for you. Now, for every activity or group I'm interested in, I've got some tiny little corner of the internet that I need to pay attention to.
Right.

Maybe I'm just an online social idiot, but this isn't working for me. Too many places and pieces. The physical analogy would be me spending all day on the road, hitting all the social hot spots in the Colorado Front Range. Ain't gonna happen. Ever.

Human Data History


The social data scene is a big stick up my butt. I really don't like it there and I'd love to get rid of it. It's poorly engineered, primitive state makes me grumpy. I don't own a thousand hammers [1]; I don't want a thousand of anything that all do basically the same thing [2]. Most of us probably don't own hundreds of houses, either (for ourselves, that is). We keep most of our stuff in the same location or two.

Speaking of houses, let's talk about settlement. How did we choose where to set up camp, towns, etc.? Trade routes, availability of resources (direct physical presence or presence by virtue of trade routes). Are we doing that now on the internet? Are we looking at the analog to fertile valleys, productive rivers, and protected harbors? Whose priorities do we have in mind? As we set up virtual presences, are we in locations that benefit businesses? Or ourselves?

If we choose the latter, the businesses will come because the people are there. If we do it the other way around, we'll be looking for new virtual homes if the businesses close shop or change the rules too much.

Coming back to data (but on the same anthropological note), historically we've had distinct divisions of our data:
  • the secure location of our huts/houses/castles
  • what we presented about ourselves in adornment/fashion (public data)
  • what we could carry with us in bags/crates/vehicles
Because of their prevalence in our history, any attempt at realizing personal data in a virtual environment would do well to reflect on these. We're naturally already predisposed to such approaches; such divisions are things that anyone can intuitively grasp.

The problem is that we're all used to a single platform: our mutually agreed-upon reality. There's no such thing online yet. And if there were, who would own/run it? Monopolies are eventually overthrown. We hate them. So how do we get around this?

Reality Merges


This very naturally led to thoughts on digital lives in general. And this is more than just a question of usability or human-computer interaction. Rather, this is a question that borders on the metaphysical: how do we solve the problem of syncing divergent realities? Reality-reality interaction.

The problem shouldn't be minimalized by analogy: this isn't a "simple" matter of ensuring that the data in my address book on Google is the same as what's on my iPhone. My self-perception, many reminders of self-reflection, etc., take place as a result of various interactions I have with my surroundings: both real[3] and virtual. No problem. Except that the things that remind me are also things that others can see and interact with as well. Often, they will have associations that spark a neural cascade for them too.

I've had many conversations take place around objects in a shared environment where the name of the object was never mentioned, it was implicitly understood. When there's no shared object (or concept), we have to name the object, define it, share some basic associations, make sure that we're talking about the same thing, etc. Thats all prelude. Only with that done, can we have genuine communication take place around the given concept.

Now rinse and repeat for everything you want to talk about that revolves around or is at least related to something that exists virtually for you and isn't part of your shared, physical environment.
I can't imagine many useful general solutions to this. In fact, I can only imagine one (given our biological wiring): use what we know (in our bones) and overlay or augment our visual reality with another.

With augmented shared realities, there's no platform. You just need hardware that runs it and senses that can perceive it. Just like reality. At that point, we can start sharing what we want, allowing access to data about ourselves and what we like by dumping it into a shared perceptual space, regardless of the original data source. Merged.

Obviously, we're not there yet. We're going to need crazy improvements in mobile technology, storage, computer vision, etc. But once the technology catches up, I think we'll see some powerful needs being filled. And we might start coming out of the internet dark ages...

Conclusion


None of this is new; Pick up any number of books by Charlie Stross[4], and there's all sorts of fun to be had by exploring his ideas. But the point of this post wasn't to be new. While we're all busy enjoying the latest fad in social media, I think it's important we think about where the progressive succession of fads is taking us. At each point, there's a natural next step (more accurately, set of possible next steps). Let's look more than just one in front of us and let's not forget what our biology has made us. We may not be able to engineer truly wise decisions about our future, or even make our lives better/more efficient. But it would be nice if we could at least not make things worse :-)

Footnotes


[1] I think I have three, actually.
[2] This is one of the reasons I'm a big fan of http://ping.fm.
[3] Here I mean "real" in the "conventional" (shared) reality sense of Mahdyamikas. Ultimate reality... well, that's a topic for an entirely different sort of post...
[4] Check out his Amazon page: http://www.amazon.com/Charles-Stross/e/B001H6IW0Q/. Accelerando is probably his most praised book (and likely my favorite), but the ideas touched on in this blog post are explored in other works of his, most notably Glasshouse and Halting State.

by Duncan McGreggor (noreply@blogger.com) at March 26, 2012 02:30 PM

OpenStack at PyCon 2012 Sprints!

This is just a short post to give a shout out to some folks who are sprinting for OpenStack this year at PyCon. It's a small group, since the Folsom Design Summit and Conference is coming up in a few weeks.

One big surprise came last night when I got an email about Cisco's recent work with Layer 3 (blueprint) support in Quantum, and there were two Cisco folks here this morning to chat about that. Mark McClain (DreamHost) is digging deep into their work right now.

Yahoo! is remote-sprinting today, and they hope to be in the house tomorrow, to continue working on current improvements in DevstackPy. Mike Pittaro (La Honda Research), Jonathan LaCour and Doug Hellmann (DreamHost) are working with Yahoo! on that.

Mike Perez (DreamHost) is hacking on some additional improvements in Horizon for different storage backend representations. We've also chatted a bit about the latest efforts in Horizon for Quantum support (Michael Fork's work). Perez is also helping out tracking some bugs down in DevstackPy.

Special thanks to Mike Pittaro for improving the sprinting pages on the OpenStack wiki with links to previous work and discussions!

If you're keen on OpenStack and would like to dive in with some fellow hackers into the deep ends of Nova, Quantum, or Horizon, be sure to come by or pop in at #openstack-pycon on Freenode :-)


by Duncan McGreggor (noreply@blogger.com) at March 26, 2012 02:26 PM

OpenStack at DreamHost

So I guess this is old news now, but DreamHost is really into OpenStack :-)

(In fact, during recess, DreamHost asked if I would pass a note to OpenStack. I didn't look inside the note, but we can all guess what it said...)

I was hired specifically to work on cloud stuff here at DreamHost, and we've got a new team that's super-excited about this -- they're starting to gear up for increased contributions and community engagement, gettin' themselves some cloud. We've now got our own Launchpad team, we're working on a handful of blueprints, chatting it up on mail lists and IRC meetings -- you get the picture :-) Exciting times.

For official blog posts and other news items that highlight DreamHost's interest and involvement in OpenStack, check these out:
I'll be writing more about our OpenStack work later, but wanted to get a quick cloud-shout-out done before too much time passed...

P.S. We're hiring Python rock-stars!

P.P.S. Did I mention that DH is an AWESOME place to work? We got an award for that, two years in a row :-)


by Duncan McGreggor (noreply@blogger.com) at March 26, 2012 02:26 PM

A Conversation with Guido about Callbacks

In a previous post, I promised to share some of my PyCon conversations from this year -- this is the first in that series :-)

As I'm sure many folks noticed, during Guido van Rossum's keynote address at PyCon 2012, he mentioned that he likes the way that gevent presents asynchronous usage to developers taking advantage of that framework.

What's more, though, is that he said he's not a fan of anything that requires him to write a callback (at which point, I shed a tear). He continued with: "Whenever I see I callback, I know that I'm going to get it wrong. So I like other approaches."

As a great lover of the callback approach, I didn't quite know how to take this, even after pondering it for a while. But it really intrigued me that he didn't have the confidence in being able to get it right. This is Guido we're talking about, so there was definitely more to this than met the eye.

As such, when I saw Guido in the hall at the sprints, I took that opportunity to ask him about this. He was quite generous with his time and experiences, and was very patient as I scribbled some notes. His perspective is a valuable one, and gave me lots of food for thought throughout the sprints and well into this week. I've spent that intervening time reflecting on callbacks, why I like them, how I use them, as well as the in-line style of eventlet and gevent [1].


The Conversation

I only asked a few initial questions, and Guido was off to the races. I wanted to listen more than write, so what I'm sharing is a condensed (and hopefully correct!) version of what he said.

The essence is this: Guido developed an aesthetic for reading a series of if statements that represented async operations, as this helped him see -- at a glance -- what the overall logical flow was for that block of code. When he used the callback style, logic was distributed across a series of callback functions -- not something that one can see at a glance.

However, more than the ability to perceive the intent of what was written with a glance is something even more pragmatic: the ability to avoid bugs, and when they arise, debug them clearly. A common place for bugs is in the edge cases, and for Guido those are harder to detect in callbacks than a series of if statements. His logic is pretty sound, and probably generally true for most programmers out there.

He then proceded to give more details, using a memcache-like database as an example. With such a database, there are some basic operations possible:

  • check the cache for a value
  • get the value if present
  • add a value if not present
  • delete a value
At first approach, this is pretty straight-forward for both approaches, with in-line yielding code being more concise. However, what about the following conditions? What will the code look like in these circumstances?
  • an attempt to connect to the database failed, and we have to implement reconnecting logic
  • an attempt to get a lock, but a key is already locked
  • in the case of a failed lock, do re-trys/backoff, eventually raise an exception
  • storing to multiple database servers, but one or more might not contain updated data
  • this leaves the system in an inconsistent state and requires a all sorts of checking, etc.
I couldn't remember all of Guido's excellent points, so I made some up in that last set of bullets, but the intent should be clear: each of those cases requires code branching (if statements or callbacks). In the case of callbacks, you end up with quite a jungle [2]... a veritable net of interlacing callbacks, and the logic can be hard to follow.

One final point that Guido made was that batching/pooling is much simpler with the in-line style, a point I conceded readily.

A Tangent: Thinking Styles

As mentioned already, this caused me to evaluate closely my use of and preference for callbacks. Should I use them? Do I really like them that much? Okay, it looks like I really do -- but why?

Meditating on that question revealed some interesting insights, yet it might be difficult to convey -- please leave comments if I fail to describe this effectively!

There are many ways to describe how one thinks, stores information in memory, retrieves data and thoughts from memory, and applies these to the solutions of problems. I'm a visual thinker with a keen  spacial sense, so my metaphors tend follow those lines, and when reflecting on this in the context of using and creating callbacks, I saw why I liked them:

The code that I read is just a placeholder for me. It happens to be the same thing that the Python interpreter reads, but that's a happy accident [3]; it references the real code... the constructs that live in my brain. The chains of callbacks that conditionally execute portions of the total-possible-callbacks net are like the interconnected deer paths through a forest, like the reticulating sherpa trails tracing a high mountain side, like the twisty mazes of an underground adventure (though not all alike...). 

As I read the code, my eyes scan the green curves and lines on a black background and these trigger a highly associative memory, which then assembles a landscape before me, and it's there where I walk through the possibilities, explore new pathways, plan new architectures, and attempt to debug unexpected culs-de-sac. 

Even stranger is this: when I attempt to write "clean" in-line async code, I get stuck. My mental processes don't fire correctly. My creative juices don't flow. The "inner eye" that looks into problem spaces can't focus, or can't get binocular vision. 

The first thing I do in such a situation? Figure out how I can I turn silly in-line control structures into callback functions :-)  (see footnote [1]),

Now What?

Is Guido's astute assessment the death of callbacks? Well, of course not. Does it indicate the future of the predominant style for writing async Python code? Most likely, yes.

However, there are lots of frameworks that use callbacks and there are lots of people that still prefer that approach (including myself!). What's more, I'd bet that the callbacks vs. in-line async style comes down to a matter of 1) what one is used to, and possibly, 2) the manner in which one thinks about code and uses that code to solve problems in a concurrent, event-driven world.

But what, as Guido asked, am I going to do with this information?

Share it! And then chat with fellow members of the Twisted community. How can we better educate newcomers to Twisted? What best practices can we establish for creating APIs that use callbacks? What patterns result in the most readable code? What patterns are easiest to debug? What is the best way to debug code comprised of layers of callbacks?

What's more, we're pushing the frontiers of Twisted code right now, exploring reactors implemented on software transaction memory, digging through both early and recent research on concurrency and actor models, exploring coroutines, etc. (but don't use inlineCallbacks! Sorry, radix...). In other words, there's so much more to Twisted than what's been created; there's much more that lies ahead of us.

Regardless, Guido's perspective has highlighted the following needs within the Twisted community around the callback approach to writing asynchronous code: 
  • education
  • establishing clear best practices
  • recording and publicizing definitive design patterns
  • continued research
These provide exciting opportunities for big-picture thinkers for both those new to Twisted, as well as the more jaded old-timers. Twisted has always pushed the edge of the envelope (in more ways than one...), and I see no signs of that stopping anytime soon :-)


Footnotes

[1] In a rather comical twist of fate, I actually have a drafted blog post on how to write gevent code using its support for callbacks :-) The intent of that post will be to give folks who have been soaked in the callback style of Twisted a way of accepting gevent into their lives, in the event that they have such a need (we've started experimenting with gevent at DreamHost, so that need has arisen for me).

[2] There's actually a pretty well-done example of this in txzookeeper by Kapil Thangavelu. Kapil defined a series of callbacks within the scope of a method, organizing his code locally and cleanly. As much as I like this code, it is probably a better argument for Guido's point ;-)

[3] Oh, happy accident, let me count the hours, days, and weeks thy radiant presence has saved me ...


by Duncan McGreggor (noreply@blogger.com) at March 26, 2012 01:49 PM

March 17, 2012

Thomas Vander Stichele

DAD hacking

On the bad side of life, I was planning to go to an awesome Calcotada in Lleida today, but I spent last night awake until 4:30 with an upset stomach, so I had to cancel and stay home feeling like shit.

On the good side of life, I really had no excuse left to not do a little long overdue hacking on Digital Audio Database.

I still use it regularly to listen to music, but the GNonLin-based player is just really not very stable. I should really just rewrite it using simply adder just like roughly ten years ago, but my brain won’t be able to do that. So instead I decided to clean up the web-based WebSockets using player I prototyped at OVC last year.

I started with some refactoring, clearly defining model/view/controller base classes and adapting the player and playerview classes to them.

WebSocket code seems to need an update every few months – I pulled the latest revision of txWebsocket on my fork, so my recent browsers actually play music again.

Since the last time I hacked on this, I actually added my 1500+ freshly ripped cd’s, in FLAC format – which browsers don’t actually support.

So, first off, I added an option for the scheduler – responsible for picking tracks, and picking audio files to represent them – to filter by extension. It’s not ideal, but it will do for now, and I punched that filter through the levels of abstraction in DAD. I now start it filtering on .mp3 and .oga, and so Chrome can play back all the tracks the scheduler throws at it.

The web-based player just loads tracks and timing info from the scheduler relative to page load time. I’ve been wanting to make that absolute for a while, so I did just that – the player server schedules tracks for epoch seconds now through websockets.

I had an entertaining half hour listening to the awesome echo effects obtained by having three chrome pages simultaneously playing the jukebox schedule – each page being slightly out of sync with the others.

As I’ll be wanting to use a smallish computer for music playback using a browser, I adapted the code to not use localhost any longer, but do everything with relative URL’s. Voila – the laptop now plays music too, a little bit more out of sync, and of course through its own speakers, adding to the eerie effect.

As an encore, I wanted to stumble my way through some jquery code, to which I’m a certified newbie. I want a nice background slideshow related to the current artist, and I pulled together echonest and bgstretcher-2 as an experiment.

That seems to work relatively well, except that the slideshow plugin doesn’t let you reload a new set of images to cycle through. And some of the other ones I tried instead after that seemed to have the same problem.

Oh well, it’s a start. If anyone knows of a good jquery background slideshow plugin that lets me update the list of url’s for images at any time, let me know!

by Thomas at March 17, 2012 11:06 PM

Duncan McGreggor

Python for iOS

I do a lot of traveling, and I don't always like to lug my laptop around with me. Even when I do, I'd rather leave it in the bag unless I absolutely need to get it out (or if I'm setting up my mobile workspace). As such, I tend to use my iPhone for just about everything: reading, emails, calendar, etc.

So, imagine my delight, when I found out (just after PyCon this year) that I can now run Python 2.7.2 on my iPhone (and, when I get it, my iPad 3 ;-) ). This is just too cool for words... and given what pictures are worth, I'll use those instead :-)

I've put together a small Flickr set that highlights some of the functionality offered in this app, and each image in the set describes a nifty feature. For the image-challenged, here's a quick list:

  • an interactive Python prompt for entering code directly using the iPhone keyboard
  • a secondary, linear "keyboard" that one can use in conjunction with the main keyboard, extending one's ability to type faster
  • multiple options for working with/preserving one's code (email, saving to a file, viewing command history)
I can't even begin to count the number of times such an awesome Python scratchpad would have come in handy. And now we have it :-) At $2.99, this is a total steal.

Thanks Jonathan Hosmer!

(And thanks to David Mertz for pointing it out to folks on a Python mail list.)



by Duncan McGreggor (noreply@blogger.com) at March 17, 2012 08:50 PM

March 16, 2012

Duncan McGreggor

PyCon 2012: To Be Continued

PyCon was just fabulous this year.

It's been a couple years since I was able to go, and I was quite surprised by how much I had been missing it. The Python community is not only one of the most technically astute and interesting ones to which I belong, but also the kindest. That last point is so incredibly important, and it ends up fostering a very strong familiar sense amongst its members.

There were so many good conversations with such great people: Anna, Alex, Guido, David (Mertz), Donovan, JP, Maciej, Allen, Glyph, Paul, Sean... the list goes on and on! Fortunately, I took notes and (and even have some book recommendations to share!) so there are many blog posts to come :-)

But this has brought something into focus quite strongly for me: the interaction at PyCon is one of the most fertile grounds for me all year -- and going without it since Chicago has been a genuine drought! There were some folks at DreamHost that couldn't make it, and we've already started looking around at various local, mini Python conferences that we can attend. This was initially so that those who couldn't make PyCon could receive similar benefits. But now there's something equally important that's contributing to the importance of this search: attending local conferences will mean not as much time has to pass between those fertile interactions and that recharging that we give each other at such events.

Until next time, I hope all Pythonistas everywhere are getting ready for a great weekend :-) Those who have been traveling, I hope you get lots of rest and share with everyone the treasures gathered at this year's PyCon :-)


by Duncan McGreggor (noreply@blogger.com) at March 16, 2012 06:43 PM

March 13, 2012

Moshe Zadka

PyCon Wrap-Up

First, my public-service announcement: if you went to PyCon, please make sure to answer the PyCon 2012 survey.

Second, my self-service: my crashing talk and lightning brain-hack talk.

Now that this is out of the way — this was a unique PyCon for me in many ways. First PyCon I could commute to, instead of staying in a hotel. I’m still torn about what I want to do for next year — commuting has advantages, but so does staying in a hotel. Driving 30 minutes back and forth was decidedly not fun. Being a local with a car was decidedly fun — being a local with a car who has been to this convention center 3-4 times before was even more fun. I knew the area, I could help others out and so on.

The other way it was unique is that I had tons of colleagues in this PyCon. There was the constant temptation to sit with them for lunch, and the constant fun of introducing them to everyone. I also tried my hand at recruiting at this PyCon, with limited success.

The last way it was special, if not quite unique, is that I have given a talk after 3 conferences where I did not. I forgot how much work it is to prepare a talk, and how nervous it makes me. Actually giving a talk is fun, but preparing for it was a bit nerve-wrecking. I was tweaking the presentation until the last day, making sure that it was exactly what I wanted. I definitely have tons of ideas for next year’s presentation. I also intend to submit a poster session — those were a lot of fun. I’ll probably try to go in with a partner for the poster session though.

On Friday, I thought it would be my “duty day”. I chaired a few sessions, and then had to give my talks. The keynotes were awesome, and the talks I chaired ranged between OK and Good (nothing that blew me out of the water, but nothing that had me going “oh, dear lord, make it stop”). What was apparently a mistake in the schedule had every speaker get an extra 10 minutes — that they used well, so I did not mind. For my talk, I was really happy with the way the green room worked this time. The runner took my laptop, connected it and all I had to worry was about getting wired up and then talking. I have to say, watching my video was kinda disappointing — I definitely need to do better on the “um”, “like” and “uuuuh” fronts. A lot of people liked my talk, though. At the Loggly party, I ate, and talked to a lot of fun people. After 90 minutes of it, I was full, I was starting to get tired and drove back home.

On Saturday, I gave a lightning talk in the morning. That was kind of an awesome experience, giving a talk to a room this big. Of course, only the non-commuters who knew how awesome lightning talks are were there, but still. I then hung out in the green room which was awesome/mistake, as I got roped into chairing the session where one talk was opposite of the “shooting squirrels with water guns” talk (guess why nobody volunteered to chair it). It was an OK session, all in all, though I thought the talk that was basically reading out loud a PyPI howto was mildly meh. For dinner, I went with a friend to the Mongolian Grill place, and then came back for my birthday. That was pretty awesome, partially because I got to introduce my wonderful wife to everyone.

Sunday had way more people in the lightning talks, and was kind of a short day. I drove to the Subway place for take-outs with a couple of people from the Twisted sprints, and then helped the Twisted newbies get started. I finally crashed and decided to go home and get a good night’s rest.


by moshez at March 13, 2012 06:49 PM

Make Sure Your Applications Crash

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.

Alternative formats:

Abstract

Applications can crash, hang or get stuck in infinite loops — even if they are written in Python. While it is good to make efforts to reduce their chances of crashing, it is also good to make sure that detection and recovery scenarios are in place for those times when something goes wrong.

Introduction

It is more and more popular to write long-running server processes in Python. Especially on unattended appliances, it is important to detect crashes and hangs, and recover from them. In the words of A. L. Scherr, “a system failure can usually be considered to be the result of two program errors: the first, in the program that started the problem; the second, in the recovery routine that could not protect the system.” (“Functional Structure of IBM Virtual Storage Operating Systems, Part II: OS/VS-2 Concepts and Philosophies,” IBM Systems Journal, Vol. 12, No. 4.)

Failure modes are similar, no matter the application language. Segmentation faults are still possible — via bugs in the core Python interpreter or native code modules. Bugs in Python applications themselves can cause crashing because of untrapped exception (some exceptions, like MemoryError, are better off not trapped). They can also hang, when calling a system call which blocks forever. At the algorithm level, bugs like infinite loops or thread-deadlock can cause a process to be unresponsive.

A higher level mode, sometimes caused as a result of trapping an unexpected exception, is a process that is an inconsistent state, and can no longer serve its purpose. Those process appear as alive to most crash-detection alorithms — for example, they will appear to have their mainloop running, and any heart-beat task will still run. This means that there must be application-level crash detectors for proper error recovery.

Data Consistency

After a process crash, and after a presumed process start-up, the data might be in an incosistent state. A process can crash during any update of permanent storage. The easiest way to ensure data consistency is to have none. Any process that can be written to rely on data from other sources rather than maintaining its own should be so written. For performance reasons, it is sometimes useful to maintain a cache. As long as cache data can be reliably rebuilt, any recovery process can rebuild it, and not have to worry about its consistency. If permanent storage is necessary, it is best if it is kept consistent by using atomic operations. The most popular way to do so is by using a transactional database, although care must be given to considering the case of the database’s crash recovery procedures. On a UNIX system, taking advantage of the fact that file move is atomic can be useful:

def update_counter():
    fp = file("counter.txt")
    s = fp.read()
    counter = int(s.strip())
    counter += 1
    # If there is a crash before this point,
    # no changes have been done.
    fp = file("counter.txt.tmp", 'w')
    print >>fp, counter
    fp.close()
    # If there is a crash before this point,
    # only a temp file has been modified
    # The following is an atomic operation
    os.rename("counter.txt.tmp", "counter.txt")

However, the last line would not work correctly on a Windows system — rename cannot take over an existing files. In cases such as these, it is possible to make the data inconsistent as long as any inconsistency can be detected at recovery time:

def update_counter():
    fp = file("counter.txt")
    s = fp.read()
    counter = int(s.strip())
    counter += 1
    # If there is a crash before this point,
    # no changes have been done.
    fp = file("counter.txt.tmp", 'w')
    print >>fp, counter
    fp.close()
    # If there is a crash before this point,
    # only a temp file has been modified
    os.remove("counter.txt")
    # At this point, the state is inconsistent*
    # The following is an atomic operation
    os.rename("counter.txt.tmp", "counter.txt")

def recover():
    if not os.path.exists("counter.txt"):
        # The permanent file has been removed
        # Therefore, the temp file is valid
        os.rename("counter.txt.tmp", "counter.txt")

In production code, we would also remove the spurious temp file if it was written but the counter file has not yet been removed — but this is not strictly needed. The only necessary thing is to fix the consistency problem if a crash happened at the point marked with an asterix.

A different technique is to use versioning, and have a janitorial process take care of obsolete versions:

def update_counter():
    files = [int(name.split('.')[-1])
                  for name in os.listdir('.')
                      if name.startswith('counter.')]
    last = max(files)
    counter = int(file('counter.%s' % last).read().strip())
    counter += 1
    # If there is a crash before this point,
    # no changes have been done.
    fp = file("tmp.counter", 'w')
    print >>fp, counter
    fp.close()
    # If there is a crash before this point,
    # only a temp file has been modified
    os.rename('tmp.counter', 'counter.%s' % (last+1))
    os.remove('counter.%s' % last)

# This is not a recovery routine, but a cleanup routine
# Even in its absence, the state is consistent
def cleanup():
    files = [int(name.split('.')[-1])
                  for name in os.listdir('.')
                      if name.startswith('counter.')]
    files.sort()
    files.pop()
    for n in files:
        os.remove('counter.%d' % n)
    if os.path.exists('tmp.counter'):
        os.remove('tmp.counter')

A variant on this method allows us to keep key/value stores in rotating log files:

0.log:
  ['add', 'key-0', 'value-0']
  ['add', 'key-1', 'value-1']
  ['add', 'key-0', 'value-2']
  ['remove', 'key-1']
  .
  .
  .

1.log:
  .
  .
  .

2.log:
  .
  .
  .

The code for dealing with those files is simple, and needs little special recovery:

## First, some utility functions:

## Get the level of a file
def getLevel(s)
    return int(s.split('.')[0])

## Get all files of a given type
def getType(tp):
    return [(getLevel(s), s)
                 for s in files if s.endswith(tp)]

## Get all relevant files
def relevant(d):
    files = os.listdir(d):
    mlevel, master = max(getType('.master'))
    logs = getType('.log')
    logs.sort()
    return master+[log for llevel, log in logs if llevel>mlevel]

## Read in a single file
def update(result, fp):
    for line in fp:
        value = json.loads(line)
        if value[0] == 'add':
            result[value[1]] = value[2]
        else:
            del result[value[1]]

## Read in several files
def read(files):
    result = dict()
    for fname in files:
        try:
            update(result, file(fname))
        except ValueError:
            pass
    return result

## The actual data store abstraction.
class Store(object):
    def __init__(self):
        files = relevant(d)
        self.result = read(files)
        self.fp = None
        self.level = getLevel(files[-1])
        self._next()
    def _next(self):
        self.level += 1
        if self.fp:
            self.fp.close()
        self.fp = file('%3d.log' % self.currentLevel, 'w')
        self.rows = 0
    def get(self, key):
        return self.result[key]
    def add(self, key, value):
        self._write(['add', key, value])
    def _write(self, value):
        print >>fp, json.dumps(value)
        fp.flush()
        self.rows += 1
        if self.rows>200:
            self._next()
    def remove(self, key):
        print >>fp, json.dumps(['remove', key])
        fp.flush()

## This should be run periodically from a different thread
def compress(d):
    files = relevant(d)[:-1]
    if len(files)<2:
        return
    result = read(files)
    master = getLevel(files[-1])+1
    fp = file('%3d.master.tmp' % master, 'w')
    for key, value in result.iteritems():
        print >>fp, json.dumps(['add', key, value])
    fp.close()

If we need to keep an efficient cache of this, we can initialize the cache only in cases where it is inconsistent. For example, we can wrap the store in a function that notes cache inconsistency, then updates the cache and then removes the inconsistency note. If the inconsistency note is there, we can reinitialize the cache.

If we are using a database with no transaction support, such as Redis or the log/master store above, and we need to modify multiple things, we can take advantage of using correct orderings, and again add code in the recovery case:

def activate_due():
    scheduled = rs.smembers('scheduled')
    now = time.time()
    for el in scheduled:
        due = int(rs.get(el+':due'))
        if now<due:
            continue
        rs.sadd('activated', el)
        rs.delete(el+':due')
        rs.sremove('scheduled', el)

def recover():
    inconsistent = rs.sinter('activated', 'scheduled')
    for el in inconsistent:
        rs.delete(el+':due') #*
        rs.sremove('scheduled', el)

Note that keeping the order of operations is important even in the recovery code — if the line marked with an asterix was to follow, rather than precede, the next line, crashing at that line would result in an element which is not scheduled but which does have a “due” attribute.

After using some subset of the techniques above to ensure data consistency, it is best to avoid scheduling tasks for “process shutdown”. This way, all process shutdowns, planned or not, will behave the same way and will therefore be easier to test. Indeed, such an attitude will lead to more bad-shutdown bugs being discovered during testing and therefore more bad-shutdown bugs being fixed. Together with a strong attempt to use mocking to make sure that every line inside the critical routines that handle data modification can be crash point, correct behavior in the face of arbitrary shutdowns can be ascertained.

Availability

After the data consistency problem is dealt with, the only result of a process crash is temporary unavailability of functionality. At its worst, the user could restart the system entirely. The two problems with such a scenario are that user intervention should not be assumed, and such a method of recovery would take too long — both the time the user takes to notice the problem, and the reboot time. Other than attempting to avoid crashes, increasing availailability means decreasing the effect crashes have on the behavior of the system. This is done by limiting the impact of a crash itself, detecting a crash as soon as possible and recovering from a crash after it has been detected as quickly as possible.

Reducing crash impact can be done in two, not mutually exclusive way — so-called vertical or horizontal process splitting. Splitting processes vertically means running the same code in multiple processes, and allocating responsibility for tasks using some sort of allocator. The most famous examples of such splitting is in network server processes, where each process handles some subset (sometimes only one) network connection. In those servers, problems in one process only effect the network connections handled by this process, and other processes continue the same. However, any task where communications between different parallel execution streams can be divided in this way:

def forking_server():
    s = socket.socket()
    s.bind(('', 8080))
    s.listen(5)
    while True:
        client = s.accept()
        newpid = os.fork()
        if newpid:
            f = client.makefile()
            f.write("Sunday, May 22, 1983 18:45:59-PST")
            f.close()
            os._exit()

Splitting processes horizontally means running different code bases in different processes — letting each process deal with one sort of task, and communicate its results, possibly, to other processes. Even in the example above, we saw such a division — the load balancer process only did load balancing, while the network server processes executed the application-specific code. We can stretch splitting further — in a web server, we often divide the processes into load-balancing, front-end web application, back-end web services and database services. A crash in the back-end will cause the front-end to retry connecting, and so the application will look slow, but not unavailable, to the end user.

In many of the cases of splitting processes, we need some form of communication between the processes. If communication can be avoided, this will minimize the effects one process has on another. It is often the case that direct communication can be avoided in favor of a shared store. While introducing subtle data update order, if we have a shared store (that properly recovers its data after crashes) we can use it to implicitly communicate between two processes by one process leaving data for another process to consume. An example can be a back-end service that calculates information offline, and feeds the information into a database that the front end queries. Crashes in either the front-end or the back-end then do not impact the other process:

## Process one
class SchedulerResource(resource.Resource):
    isLeaf = True
    def __init__(self, filepath):
        resource.Resource.__init__(self)
        self.filepath = filepath
    def render_PUT(self, request):
        uuid, = request.postpath
        content = request.content.read()
        self.filepath.child(uuid).setContent(content)
s = server.Site(SchedulerResource(filepath.FilePath("things")))
reactor.listenTCP(8080, s)

## Process two
rs = redis.Redis(host='localhost', port=6379, db=9)
while True:
    for fname in os.listdir("things"):
        when = int(file(fname).read().strip())
        rs.set(uuid+':due', when)
        rs.sadd('scheduled', uuid)
        os.remove(fname)
    time.sleep(1)

## Process three
rs = redis.Redis(host='localhost', port=6379, db=9)
recover()
while True:
    activate_due()
    time.sleep(1)

If implicit communication using shared storage is inadvisable, a message queue can often be helpful. Message queues have the advantage of being a fairly reliable infrastructure, and allowing for application process connecting and disconnecting:

## Process four
rs = redis.Redis(host='localhost', port=6379, db=9)
channel = pika.BlockingConnection(pika.ConnectionParameters(
              'localhost')).channel()
channel.queue_declare(queue='active')
while True:
    activated = rs.smembers('activated')
    finished = set(rs.smembers('finished'))
    for el in activated:
        if el in finished:
            continue
        channel.basic_publish(exchange='',
                              routing_key='active',
                              body=el)
        rs.add('finished', el)

## Process five
# It is possible to get "dups" of bodies.
# Application logic should deal with that
channel = pika.BlockingConnection(pika.ConnectionParameters(
              'localhost')).channel()
channel.queue_declare(queue='active')
def callback(ch, method, properties, el):
    syslog.syslog('Activated %s' % el)
channel.basic_consume(callback, queue='hello', no_ack=True)
channel.start_consuming()

If point-to-point connections are desirable, web-based communications have the benefit of being easily restartable, especially when using RESTful APIs.

Especially in the case of horizontal splitting, it is crucial to make sure that any given service is available. Unavailability means either a front-end is not functioning, which causes user-visible failing, or some queue not being processed properly. A basic way to do so is to monitor the process itself being alive. On UNIX systems, this can be as simple as sending a “kill 0″ to the process periodically, and checking that there are no errors. However, such process liveness checks will not detect a process that is stuck in an infinite loop.

A better way is to send and detect heartbeats. The simplest heart-beats are simply files which are touched in regular intervals:

## In a Twisted process
def beat():
    file('beats/my-name', 'a').close()
task.LoopingCall(beat).start(30)

## Watchdog
while True:
    now = time.time()
    timeout = dict()
    for heart in glob.glob('hearts/*'):
        beat = int(file(heart).read().strip())
        timeout[heart] = now-beat
    for heart in glob.glob('beats/*'):
        if not os.path.isfile(heart):
            mtime = 0
        else:
            mtime = os.path.getmtime(heart)
        problem = 'problems/'+heart
        if (mtime<timeout[heart] and
           not os.path.isfile(problem)):
            fp = file('problems/'+heart, 'w')
            fp.write('watchdog')
            fp.close()
    problemTimeout = now-30
    for problem in glob.glob('problems/*'):
        if os.path.getmtime(problem)<problemTimeout:
            subprocess.call(['restart-system'])
    time.sleep(1)

In this watchdog example, we assume that the actual process restart is done by some dedicated process manager. Our watchdog process is only responsible for detecting the problems, as well as restarting the whole system if the manager itself seems stuck. Note that a proper implementation of restart-system is non-trivial — it needs to track down and kill each part of the old system.

Note that the watchdog never tries to be the sole source of truth regarding problems — it merely checks that every problem was appropriately dealt with. This means that there is an opportunity for a system to include high-level checkers — things that check liveness by, for example, sending test requests and checking that these are dealt with in a reasonable manner. If the the test request hangs or fails, the checker can manufacture a problem.

On a real production system, the watchdog process would not be its own main loop — it would be called from something like cron, so that a single loop failing would not cause the watchdog itself to fail. For extra reliability, the watchdog command can end with touching a file. On Linux systems, not touching this file often enough can be set to cause a reboot using the Linux “watchdog” daemon.

If problems are properly detected, and hanging processes are restarted, it is good to have processes come up as fast as possible. If it is at all possible, processes should not depend on each other during start-up — for example, consistency checks should usually precede connecting to the message queue, as this allows the message queue to come up while the consistency checks are running.

Conclusions

Everything can crash, and usually will. While fixing bugs to avoid crashes is a good idea, planning for the inevitable is even more important and can keep a system running with minimal user-visible interruption.

<a rel=”license” href=”http://creativecommons.org/licenses/by/3.0/”><img alt=”Creative Commons License” style=”border-width:0″ src=”http://i.creativecommons.org/l/by/3.0/80×15.png” /></a><br />This work is licensed under a <a rel=”license” href=”http://creativecommons.org/licenses/by/3.0/”>Creative Commons Attribution 3.0 Unported License</a>.


by moshez at March 13, 2012 11:33 AM

March 12, 2012

Moshe Zadka

Better Technical Talks

This is a follow-up for my earlier post.

Here I intend to give some practical advice! But first, allow me to digress — why are you up there speaking, and why are these people listening to you?

If they really were consumed by a desire to know, they would read your blog posts about the topic. They are not there because they are missing knowledge. They are there because they think you will be entertaining. Optimize for being entertaining, and you might be able to teach them something. Optimize for teaching, and you will probably be boring, and they will learn nothing.

Remember: public speaking is a performance art. Treat your technical talk as a performance, and you will do much better. Now, performance doesn’t mean you make it into a circus: you want to give the audience what they expect, more or less. In a technical talk, they expect to be fascinated by stories of the interaction between computers and people.

Hollywood writing has a concept called “Save the Kitten”. Near the beginning of the movie, the hero does something good (“saving the kitten”) which makes the audience care about him. Now, when he does something stupid and has to go on a quest to fix it, you care enough about him to follow along. Likewise, you need to set yourself up as a hero in the beginning of the talk — subtly.

The talk I went to about metaclasses set the speaker as a hero because he outlined a Prometheus narrative of bringing fire from the Gods to the mortals. The talk about stopping to write classes set the hero as the person who helps clean up other people’s code. In my talk, I told a story about visiting a customer and seeing how they didn’t notice many errors because of our crash recovery system. I could outline many other examples, but this ultimately has to be about you.

Apologies are rarely entertaining. If you are already a good speaker, you can usually find an entertaining way to apologize but as a novice just refrain from that at all. A self-deprecating joke would do much better if something screwed up.

  • Wrong: “Sorry, I completely forgot to talk about something 3 slides ago…”
  • Right: “Oh, hey, three slides ago I should have told you something else. Let’s go jump in the time machine and fix it…”

Put pictures on your slides. People like looking at pictures. Have them somewhat related to your talk, although it’s ok if the connection is obscure. Puzzled people are a bit distracted, but they are not bored. They might not listen to you — but at least they will not walk away thinking that they are glad to have caught up on their sleep.

Put less words on your slides. If you must put words, have them be a “teaser” that you explain. There is a reason shows on TV starts with a teaser — people will keep their attention to find a solution. If you put code, try to make it less than 10 lines, including comments. It is ok to use code in a style that would not pass muster in production to illustrate a point.

Practice your talk. Do it in front of a video camera. I am still working on reducing my “ums” and “likes”. Accents, however, are not bad. Sure, they make the audience work harder to understand you, which works against the “teaching” goal. But they work for the “entertaining” goal because, let’s face it, accents are funny.

Lastly, remember that unless you’re the human cannon, people are not watching you to see you fail. They want to see you succeed. Draw confidence from people, not fear.

 


by moshez at March 12, 2012 03:04 PM

March 06, 2012

Donovan Preston

Where are the Peer-to-Peer web apps?

Perhaps the reason we have not seen single-page html applications that connect directly to peers without an intermediate server is that browsers cannot easily listen on a local port. They can open outgoing connections all day long, but WebRTC may be the first web standard that allows the browser to listen on a port. If there are others, please let me know.

Of course, the WebRTC spec looks overly complicated for the incredibly simple thing I want to do. I just want the browser to be able to listen on a port like any other process on the machine can. Sure, there are security implications, but these exist for everything the browser exposes to web applications, and there's an entire class of Peer-to-Peer web apps that simply cannot easily be written using current web technologies.

There are many examples of a Peer-to-Peer experience being delivered to users using a client-server architecture. ChatRoulette, Omegle, and even more recently, products like Google Hangouts. These applications must be implemented by using servers in the middle to connect the peers, making scaling them much harder than it would be if browsers could just listen.

There is an opportunity to explore a generic Client-Agent-Peer architecture, where Clients (Browsers) talk to an Agent server using HTTP to configure the state of the Agent, which would then be contacted by the Peer on behalf of the Client when the Browser is not online. When the Browser is online, the Agent can refer the Peer directly to the Client. When the Browser is offline, the Agent can handle the request itself using a cached copy of the material the Browser was sharing, or it can just decline to fulfill the request.

Reverse HTTP was my attempt to push out the simplest thing that could possibly work to get browsers to talk to each other. It didn't really go anywhere in terms of being implemented in actual browsers. Coincidentally, someone else had the same idea around the same time, and implemented Reverse HTTP in terms of actual HTTP Requests encoded in Responses, and vice versa. This makes it possible to write a pure javascript client rather than needing the browser to support the Upgrade protocol itself.

Really, though, it would be very nice if all of the hacks and tricks and workarounds weren't necessary, and I could just listen on a port with javascript. I'll keep dreaming.

by Donovan Preston (noreply@blogger.com) at March 06, 2012 02:55 AM

March 04, 2012

Thomas Vander Stichele

More adventures in puppet

After last week’s Linode incident I was getting a bit more worried about security than usual. That coincided with the fact that I found I couldn’t run puppet on one of my linodes, and some digging turned up that it was because /tmp was owned by uid:gid 1000:1000. Since I didn’t know the details of the breakin (and I hadn’t slept more than 4 hours for two nights, one of which involving a Flumotion DVB problem), I had no choice but to be paranoid about it. And it took me a good half hour to realize that I had inflicted this problem on myself – a botched rsync command (rsync arv . root@somehost:/tmp).

So I wasn’t hacked, but I still felt I needed to tighten security a bit. So I thought I’d go with something simple to deploy using puppet – port knocking.

Now, that would be pretty easy to do if I just deployed firewall rules in a single set. But I started deploying firewall rules using the puppetlabs firewall module, which allows me to group rules per service. So that’s the direction I wanted to head off into.

On saturday, I worked on remembering enough iptables to actually understand how port knocking works in a firewall. Among other things, I realized that our current port knocking is not ideal – it uses only two ports. They’re in descending order, so usually they would not be triggered by a normal port scan, but they would be triggered by one in reverse order. That is probably why most sources recommend using three ports, where the third port is between the first two, so they’re out of order.

So I wanted to start by getting the rules right, and understanding them. I started with this post, and found a few problems in it that I managed to work out. The fixed version is this:
UPLINK="p21p1"
#
# Comma seperated list of ports to protect with no spaces.
SERVICES="22,3306"
#
# Location of iptables command
IPTABLES='/sbin/iptables'

# in stage1, connects on 3456 get added to knock2 list
${IPTABLES} -N stage1
${IPTABLES} -A stage1 -m recent --remove --name knock
${IPTABLES} -A stage1 -p tcp --dport 3456 -m recent --set --name knock2

# in stage2, connects on 2345 get added to heaven list
${IPTABLES} -N stage2
${IPTABLES} -A stage2 -m recent --remove --name knock2
${IPTABLES} -A stage2 -p tcp --dport 2345 -m recent --set --name heaven

# at the door:
# - jump to stage2 with a shot at heaven if you're on list knock2
# - jump to stage1 with a shot at knock2 if you're on list knock
# - get on knock list if connecting t0 1234
${IPTABLES} -N door
${IPTABLES} -A door -m recent --rcheck --seconds 5 --name knock2 -j stage2
${IPTABLES} -A door -m recent --rcheck --seconds 5 --name knock -j stage1
${IPTABLES} -A door -p tcp --dport 1234 -m recent --set --name knock

${IPTABLES} -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
${IPTABLES} -A INPUT -p tcp --match multiport --dport ${SERVICES} -i ${UPLINK} -m recent --rcheck --seconds 5 --name heaven -j ACCEPT
${IPTABLES} -A INPUT -p tcp --syn -j door

# close everything else
${IPTABLES} -A INPUT -j REJECT --reject-with icmp-port-unreachable

And it gives me this iptables state:

knock

So the next step was to reproduce these rules using puppet firewall rules.

Immediately I ran into the first problem – we need to add new chains, and there doesn’t seem to be a way to do that in the firewall resource. At the same time, it uses the recent iptables module, and none of that is implemented either. I spent a bunch of hours trying to add this, but since I don’t really know Ruby and I’ve only started using Puppet for real in the last two weeks, that wasn’t working out well. So then I thought, why not look in the bug tracker and see if anyone else tried to do this ? I ask my chains question on IRC, while I find a ticket about recent support. A minute later danblack replies on IRC with a link to a branch that supports creating chains – the same person that made the recent branch.

This must be a sign – the same person helping me with my problem in two different ways, with two branches? Today will be a git-merging to-the-death hacking session, fueled by the leftovers of yesterday’s mexicaganza leftovers.

I start with the branch that lets you create chains, which works well enough, bar some documentation issues. I create a new branch and merge this one on, ending up in a clean rebase.

Next is the recent branch. I merge that one on. I choose to merge in this case, because I hope it will be easier to make the fixes needed in both branches, but still pull everything together on my portknock branch, and merge in updates every time.

This branch has more issues – rake test doesn’t even pass. So I start digging through the failing testcases, adding print debugs and learning just enough ruby to be dangerous.

I slowly get better at fixing bugs. I create minimal .pp files in my /etc/puppet/manifests so I can test just one rule with e.g. puppet apply manifests/recent.pp

The firewall module hinges around being able to convert a rule to a hash as expressed in puppet, and back again, so that puppet can know that a rule is already present and does not need to be executed. I add a conversion unit test for each of the features that tests these basic operations, but I end up actually fixing the bugs by sprinkling print’s and testing with a single apply.

I learn to do service iptables restart; service iptables stop to reset my firewall and start cleanly. It takes me a while to realize when I botched the firewall so that I can’t even google (in my case, forgetting to have -A INPUT -m state –state ESTABLISHED,RELATED -j ACCEPT
) – not helped by the fact that for the last two weeks the network on my home desktop is really flaky, and simply stops working after some activity, forcing me to restart NetworkManager and reload network modules.

I start getting an intuition for how puppet’s basic resource model works. For example, if a second puppet run produces output, something’s wrong. I end up fixing lots of parsing bugs because of that – once I notice that a run tells me something like
notice: /Firewall[999 drop all other requests]/chain: chain changed '-p' to 'INPUT'
notice: Firewall[999 drop all other requests](provider=iptables): Properties changed - updating rule

I know that, even though the result seems to work, I have some parsing bug, and I can attack that bug by adding another unit test and adding more prints for a simple rule.

I learn that, even though the run may seem clean, if the module didn’t figure out that it already had a rule (again, because of bogus parsing), it just adds the same rule again – another thing we don’t want. That gets fixed on a few branches too.

And then I get to the point where my puppet apply brings all the rules together – except it still does not work. And I notice one little missing rule: ${IPTABLES} -A INPUT -p tcp –syn -j door

And I learn about –syn, and –tcp-flags, and to my dismay, there is no support for tcp-flags anywhere. There is a ticket for TCP flags matching support, but nobody worked on it.

So I think, how hard can it be, with everything I’ve learned today? And I get onto it. It turns out it’s harder than expected. Before today, all firewall resource properties swallowed exactly one argument – for example, -p (proto). In the recent module, some properties are flags, and don’t have an argument, so I had to support that with some hacks.

The rule_to_hash function works by taking an iptables rule line, and stripping off the parameters from the back in reverse order one by one, but leaving the arguments there. At the end, it has a list of keys it saw, and hopefully, a string of arguments that match the keys, but in reverse order. (I would have done this by stripping the line of both parameter and argument(s) and putting those on a list, but that’s just me)

But the –tcp-flags parameter takes two arguments – a mask of flags, and a list of flags that needs to be set. So I hack it in by adding double quotes around it, so it looks the same way a –comment does (except –comment is always quoted in iptables –list-rules output), and handle it specially. But after some fidgeting, that works too!

And my final screenshot for the day:

knock-puppet

So, today’s result:

Now, I have a working node that implements port knocking:
node 'ana' {

$port1 = '1234'
$port2 = '3456'
$port3 = '2345'

$dports = [22, 3306]

$seconds = 5

firewall { "000 accept all icmp requests":
proto => "icmp",
action => "accept",
}

firewall { "001 accept all established connections":
proto => "all",
state => ["RELATED", "ESTABLISHED"],
action => "accept",
}

firewall { "999 drop all other requests":
chain => "INPUT",
proto => "tcp",
action => "reject",
}

firewallchain { [':stage1:', ':stage2:', ':door:']:
}

# door
firewall { "098 knock2 goes to stage2":
chain => "door",
recent_command => "rcheck",
recent_name => "knock2",
recent_seconds => $seconds,
jump => "stage2",
require => [
Firewallchain[':door:'],
Firewallchain[':stage2:'],
]
}

firewall { "099 knock goes to stage1":
chain => "door",
recent_command => "rcheck",
recent_name => "knock",
recent_seconds => $seconds,
jump => "stage1",
require => [
Firewallchain[':door:'],
Firewallchain[':stage1:'],
]
}

firewall { "100 knock on port $port1 sets knock":
chain => "door",
proto => 'tcp',
recent_name => 'knock',
recent_command => 'set',
dport => $port1,
require => [
Firewallchain[':door:'],
]
}

# stage 1
firewall { "101 stage1 remove knock":
chain => "stage1",
recent_name => "knock",
recent_command => "remove",
require => Firewallchain[':stage1:'],
}

firewall { "102 stage1 set knock2 on $port2":
chain => "stage1",
recent_name => "knock2",
recent_command => "set",
proto => "tcp",
dport => $port2,
require => Firewallchain[':stage1:'],
}

# stage 2
firewall { "103 stage2 remove knock":
chain => "stage2",
recent_name => "knock",
recent_command => "remove",
require => Firewallchain[':stage2:'],
}

firewall { "104 stage2 set heaven on $port3":
chain => "stage2",
recent_name => "heaven",
recent_command => "set",
proto => "tcp",
dport => $port3,
require => Firewallchain[':stage2:'],
}

# let people in heaven
firewall { "105 heaven let connections through":
chain => "INPUT",
proto => "tcp",
recent_command => "rcheck",
recent_name => "heaven",
recent_seconds => $seconds,
dport => $dports,
action => accept,
require => Firewallchain[':stage2:'],
}

firewall { "106 connection initiation to door":
# FIXME: specifying chain explicitly breaks insert_order !
chain => "INPUT",
proto => "tcp",
tcp_flags => "FIN,SYN,RST,ACK SYN",
jump => "door",
require => [
Firewallchain[':door:'],
]
}
}
and I can log in with
nc -w 1 ana 1234; nc -w 1 ana 3456; nc -w 1 ana 2345; ssh -A ana

Lessons learned today:

  • watch iptables -nvL is an absolutely excellent way of learning more about your firewall – you see your rules and the traffic on them in real time. It made it really easy to see for example the first nc command triggering the knock.
  • Puppet is reasonably hackable – I was learning quickly as I progressed through test and bug after test and bug.
  • I still don’t like ruby, and we may never be friends, but at least it’s something I’m capable of learning. Puppet might just end up being the trigger.

Tomorrow, I need to clean up the firewall rules into something reusable, and deploy it on the platform.

by Thomas at March 04, 2012 10:32 PM

March 02, 2012

Jonathan Lange

Local Juju

I have a bit of a fetish for being able to hack offline. It's becoming increasingly old-fashioned, I know, but I'd like to think that eventually it will become a quirky and charming eccentricity, such as one might find in a British amateur sleuth.

I wanted to get up and running with Juju, Canonical's funky cloud orchestration thingy. We're doing a lot more service-oriented stuff in recent months, and it's very handy to be to just deploy something without having to faff about for a couple of hours. Since I'd like to stand a chance of doing this without a net connection, I set it up locally.

With the help of the Charm School page, the local provider docs and the kind folk at #juju on Freenode, I got something up and running. Some notes about the experience:
  • I did all of this in precise, and it seemed to work just fine. I substituted 'precise' for 'oneiric' wherever I saw it.
  • I had to manually add my user to the libvirtd group. The instructions implied that this was not necessary.
  • juju bootstrap finished very quickly for me and without any actual evidence that it had debootstrapped the whole OS.
  • When I deployed services, I didn't get any feedback that anything was going on. The recommended debug-log command showed very little output for a while. My guess is that this was while packages were downloading.
All in all, pretty impressive. I'm really looking forward to mucking around with this a bit more

by jml (noreply@blogger.com) at March 02, 2012 04:45 PM

Duncan McGreggor

Successful Hack-In, 01 Mar 2012!

DreamHost has a new core set of cloud developers now based in Atlanta, and a new Meetup group to go with that :-) Today there was a global OpenStack Hack-In, and I just posted a summary to our Meetup discussion page, but since I desperately need to do some blogging, I'm republishing here :-) (with some minor tweaks...)

We had fun in person, there was good chatter on IRC with the Colorado and San Francisco teams, and we had a great time digging into OpenStack some more.

Technical highlights include:
  • testing out development deployments of OpenStack using Vagrant (some successes, some blockers)
  • testing out dev deployments of OpenStack using VirtualBox directly
  • filed some bugs for issues in horizon regarding error feedback to users and how the documentation is generated
  • dug into issues with logging and inconsistencies in datestamps
  • uncovered some weirdness with the usage of gnu screen and hanging services/partial devstack installs due to sudo assumptions (devstack assumes a passwordless sudo, and will label an install as failed if it gets hung up on the apache log tail, waiting for a password, even if the install was successful and all the services started correctly)
  • Doug Hellmann made his first commit upstream to OpenStack
On the non-technical, fun side:
  • Thanks for Zenoss for the fun swag today smile (the Zebras are still staring at me... I think they're going to be making an appearance in ToyStory 5)
  • Even more thanks to Zenoss for the offer to become an OpenStack Atlanta Sponsor (food, drinks, and swag)!
  • Thanks to DreamHost for the AMAZING coffee and danishes from The Village Corner Restaurant/Basket Bakery. Seriously. That was the best coffee I have ever had. In. My. Life.
  • Also, thanks DreamHost for the pizza and the sweet potato pies!


We took a couple snapshots of the event, and I'll be posting those soon on the Meetup page, but for the super-impatient, they're up on Flickr right now smile

http://www.flickr.com...


by Duncan McGreggor (noreply@blogger.com) at March 02, 2012 01:53 AM

February 27, 2012

Jp Calderone

Side Project: Crop Planning Software

Elsewhere, I wrote about the beginning of growing season and some software I've written to help us out this year. The software I was talking about is very spartan right now. It tries to serve exactly our needs, with just enough user interface so that we can get at the information we need. If you notice where exactly on Launchpad I'm currently hosting it, you'll get some idea about how much effort I've put into making this a real, distributable, useful-to-anyone-else project so far.

What the software does at this point is this:

  • Load data from a (semi-)structured file (csv, because it's easy to create and export data in this format using Open Office). The data it can load describes certain crops and certain varieties of those crops, including information about start and end of season, required growing days, anticipated yields, etc.
  • Plan out a seed order, based on that yield data and additional product data (also in the input file). Doing this without wasting a ton of money ends up being something like a solution to the covering problem, due to discounts for buying greater quantities (sometimes unbelievable discounts, with marginal costs for additional seed ranging as low as 5% of the base cost). This is also a very tedious part of the program, as common suppliers offer seed in well over a dozen different package sizes (with "packages" with the same name containing different amounts of seed for different kinds of vegetables, and of course different vegetables requiring different amounts of seed to produce a particular yield).
  • Predict various kinds of resource usage at each point in the season. Resources include things like bed feet (eg, we have 22 beds, each 100 feet long, so we have 2200 bed feet; our crop plan cannot exceed this, or we'll have plants that have nowhere to be planted), plug flag usage (where seeds are started and grow until they're hardy enough to be transplanted outside), and man hours (there are two of us, we don't want to plant so much that we would need to hire help to deal with it).
  • Generate a schedule of when to seed each variety, when to expect to transplant them outdoors, and when to harvest them. The schedule can be displayed as a list or it can be generated as an iCalendar file and loaded into something like Google Calendar or Apple's iCal.

These are all pretty basic pieces of information that someone growing vegetables would want to know. On a small scale, they're the kinds of things you can plan out in your head, or keep track of on paper. As you want to do more, though, it can be overwhelming. For example, our schedule for this season has 376 events on it. I wouldn't have wanted to generate that manually.

There is also some rudamentary graphing functionality. This is for visualizing some of the pieces of information I mentioned above (eg plug flat usage). So far this part has been mostly for fun, as it's hard to make any additional specific decisions based on the graphs, as opposed to the textual, numerical output also generated. One thing it has been useful for, though, is sanity checking the output. It's easier to see a crazy spike or a mysterious plateau on a graph than in numerical data.

As far as the implementation goes, there's nothing really fancy going on here. I've added a lot of features that I hadn't originally planned on (or realized would be useful). As I mentioned, this is a new domain for me to be working in. There is some unit test coverage now, but I didn't start out doing test-driven development. This has bitten me a few times already, as some of the scheduling logic is subtle enough that I can't change it without introducing bugs. Fortunately that part of the code is somewhat well tested now. Well, not completely untested, at least. Development has been test-driven for a month or two now, so I expect things to get easier going forward.

Everything is written in Python, of course. I used vobject to generate the iCalendar output, with pytz to help with the timezone math (oh, timezones, how I loathe you). A pleasantly small amount of code suffices for that.

I used matplotlib and dateutil to generate the graphs. I have a tolerate/hate relationship with matplotlib. It clear does a lot of stuff, and I've seen people use it to good effect. Most of its functionality escapes me, though, and I can hardly learn about a new API without observing that it is completely terrible. Still, I used it because it can do the job, and better than the other options, in my experience.

For the highly tedious structure definition, I used a class from Epsilon. epsilon.structlike.record is a lot like the Python standard library collections.namedtuple. Any time I used the latter, though, I remember how it is implemented and I feel bad. So I stick to the former.

I also used Twisted and html5lib to write a simple web scraper to turn variety names into Johnny's product identifiers. Even if ordering seeds this way ends up being a one-off task, writing the scraper to get this information was definitely easier than chasing down product identifiers in a Johnny's catalog or from the Johnny's website, which each have their own... unique approach to organization. I asked Johnny's if they could make this information available in any sort of structured format and they told me they couldn't. Maybe I should sell it back to them?

Many features are still missing from the planning software. Some of them are simple, like reporting how many flats to seed in the iCalendar event it generates, instead of just reporting how many bed feet will be used after the seeds germinate and are transplanted out into the field. Others are a bit bigger, like having a more coherent model for the underlying data. I might want to put this off until the end of the season, when I might have a better idea if I've fully understood the underlying data myself.

I don't expect this to be useful to a lot of people. In case this sort of tool does appeal to you, though, I'd love feedback (particularly from people more experienced with planning and executing these kinds of agricultural tasks) - but no feature requests, please :)

by Jean-Paul Calderone (noreply@blogger.com) at February 27, 2012 03:01 PM

Thomas Vander Stichele

Collabora and Fluendo collaborate fluently!

Well, this sure has been a long time in the making.

Fluendo and Collabora have a checkered past which I won’t get into, but on paper it has always made sense for these two companies to collaborate and making GStreamer work commercially. One company specializes in products, the other in consulting (I’m sure you can figure out which is which), and complement each other perfectly to make GSstreamer more successful commercially.

I personally have always believed that we need to get GStreamer to other platforms and make them as easy to use as possible. Windows was an obvious target in the past, and now Android is another. There is a big difference between a successful open source project, and a commercially successful one. Flumotion’s Andoni Morales who came with me to the GStreamer 0.11 hackfest in Malaga is going to be working on this one SDK to rule them all.

Christian beat me to it in the blogosphere, but the word is now officially out! Feel free to read Fluendo’s press release.

by Thomas at February 27, 2012 12:01 PM

February 25, 2012

Jonathan Lange

Bad Snake Joke

Just between you and me, I'm getting a bit bored of writing Python all the time. It's a good language: I can write code that's functional or OO as the case may be; it has lots of libraries; it has Twisted, which is incredibly useful; it's not too hard to make a big project and keep it clean. It's the least awful programming language that I know of. That said, I'd like to do something different.

I would like to play with something makes static typing rock (like Haskell), or that has what Rich Hickey calls "polymorphism a la carte" (again, like Haskell, or Clojure). I would like to make something that stands a chance of feeling snappy (perhaps PyPy?), a chance to use something with richer debugging and refactoring tools, or to get a feel for doing some serious concurrency work outside of an event loop.

But mainly, I'm just bored of Python.

Also, I increasingly suspect that Python doesn't have legs. The Python 3 language change has increased the split between the core developer community and people writing code in the field. Python continues to be slow, both with start-up time and while running. The only people who seem to care are the PyPy developers, but I doubt I'll ever get to use it for commercial development. It's tricky to write code in Python that takes advantage of multiple cores, and even my phone has multiple cores now.

When I get the chance, I'm going to do more with Haskell and Clojure in my spare time. I'm not sure if there is something less "fringe" that I could recommend for use at Canonical. Go is a possibility, if a slightly disappointing one (interfaces are cool, but why oh why didn't they do typeclasses?).

by jml (noreply@blogger.com) at February 25, 2012 01:36 PM

February 16, 2012

Jonathan Lange

testtools 0.9.14 released

testtools's sister project, subunit, was using a private API that we deleted in the 0.9.13 release.  This release restores that API in order to smooth out the upgrade path.

If you don't use subunit, then this release won't matter very much to you.

by jml (noreply@blogger.com) at February 16, 2012 10:55 AM

February 12, 2012

Glyph Lefkowitz

This Isn't How PyPy Works, But it Might as Well Be

It seems like a lot of the Python programmers I speak with are deeply confused by PyPy and can't understand how it works.  The stereotypical interlocutor will often say things like: A Python VM in Python?  That's just crazy!  How can that be fast?  Isn't Python slower than C?  Aren't all compilers written in C?  How does it make an executable?

I am not going to describe to you how PyPy actually works.  Lucky for you, I'm not smart enough to do that.  But I would like to help you all understand how PyPy could work, and hopefully demystify the whole idea.

The people who are smart enough to explain how PyPy actually works will do it over at the PyPy blog.  At some level it's really quite straightforward, but this impression of straightforwardness is not conveyed well by posts with titles like "Optimizing Traces of the Flow Graph Language".  In addition to being a Python interpreter in Python, PyPy is a mind-blowingly advanced exploration of the cutting-est cutting-edge compiler and runtime technology, which can make it seem complex. In fact, the fact that it's in Python is what lets it be so cutting-edge.

Most people with a formal computer science background are already familiar with the fairly generic nature of compilers, as well as the concept of a self-hosting compiler.  If you do have that background, then that's all PyPy is: a self-hosting compiler.  The same way GCC is written in C, PyPy is written in Python.  When you strip away the advanced techniques, that's all that's there.

A lot of folks who are confused by PyPy's existence, though, I suspect don't have that background; many working programmers these days don't.  Or if they do, they've forgotten it, because the practical implications of the CSS box model are so complex that they squeeze simpler ideas, like turing completeness and the halting problem, out of the average human brain.  So here's the easier explanation.

A compiler is a program that turns a string (source code: your program text written in Python, C, Ruby, Java, or whatever) into some kind of executable code (bytecode or runtime interpreter operations or a platform-native executable).

Let's examine that last one, since it seems to be a sticking point for most folks.  A platform-native executable is simply a bunch of bytes in a file. There's nothing magic about it.  It's not even a particularly complex type of file.  It's a packed binary file, not a text file, but so are PNGs and JPEGs, and few programmers find it difficult to believe that such files might be created by Python.  The formats are standard and very long-lived and there are tons of tools to work with them.  If you're curious, even Wikipedia has a good reference for the formats used by each popular platform.

As to Python being slower than C: once a program has been transformed into executable code, it doesn't matter how slow the process for translating it was: the running program is now just executable instructions for your CPU, so it doesn't matter that Python is slower than C, because it was just the compiler that was in Python, and by the time your program is running, the original Python has effectively vanished and all you're left with is your program executing.

(Actually, Python is faster than C anyway, especially at producing strings.)

In reality, PyPy takes a hybrid approach, where it is a program which produces a program and then does some stuff to it and creates some C code which it compiles with the compiler of your choice and then creates some code which then creates other code and then puts it into memory, not a file, and then executes it directly, but all of that is ancillary tricks and techniques to make your code run faster, not a fundamental property of the kind of thing that PyPy is.  Plus, as I said, this article isn't actually about how PyPy works anyway, it's just about how you should pretend it works.  So you should ignore this whole paragraph.

For the sake of argument, assume that you know all the ins and outs of binary executable formats for different operating systems, and the machine code for various CPU architectures.  The question you should really ask yourself is: if you have to write a program (a compiler) which translates one kind of string (source code) into another kind of string (a compiled program): would you rather write it in C or Python?  What if the strings in question were a template document and an HTML page?

It shouldn't be surprising that PyPy is written in Python.  For the same reasons that you might use Django templates and not snprintf for generating your HTML, it's easier to use Python than C to generate compiled code.  This is why PyPy is at the forefront of so many advanced techniques that are too sophisticated to cover in a quick article like this.  Since the compiler is written in a higher-level language, it can do more advanced things, since lower-level concerns can be abstracted away, just as they are in your own applications.

by glyph (noreply@blogger.com) at February 12, 2012 11:41 PM

Twisted Matrix Laboratories

Announcing Twisted 12.0

Thanks to Thomas Hervé, we are proud to announce the release of Twisted 12.0.

47 tickets are closed by this release, among them:
  • A fix to the GTK2 reactor preventing unnecessary wake-ups 
  • Preliminary support of IPV6 on the server side
  • Several fixes to the new protocol-based TLS implementation
  • Improved core documentation's main page 
Twisted no longer supports Python 2.4, the latest supported version is 2.5.

For more information, see the NEWS file here: http://twistedmatrix.com/Releases/Twisted/12.0/NEWS.txt

Download it now from:
http://pypi.python.org/packages/source/T/Twisted/Twisted-12.0.0.tar.bz2 or
http://pypi.python.org/packages/2.5/T/Twisted/Twisted-12.0.0.win32-py2.5.msi or
http://pypi.python.org/packages/2.6/T/Twisted/Twisted-12.0.0.win32-py2.6.msi or
http://pypi.python.org/packages/2.7/T/Twisted/Twisted-12.0.0.win32-py2.7.msi

Thanks to the supporters of Twisted via the Software Freedom Conservancy and to the many contributors for this release.

by Itamar Turner-Trauring (noreply@blogger.com) at February 12, 2012 01:58 AM

February 10, 2012

Thomas Vander Stichele

Rebuilding older rpms

Today I needed an xml diff tool. There seem to be an xmldiff and a diffxml, neither of them packaged by Fedora at the moment. I found an old src.rpm for Fedora 6 for xmldiff 0.6.8

The src.rpm doesn’t rebuild as is for various reasons: its %check stage imports unittest2, so I disabled check. Then it didn’t find debuglist.files, so I disabled building a debug package. And then it found an installed egg file which it didn’t like, so I disabled checking for installed files.

Since I’m going to forget how I did this in the future when I will need this again for some obscure reason, and because if you ever build rpms you may find this useful, here is the command that did it for me for Fedora 15:
rpmbuild --rebuild -D '%check exit 0' -D 'debug_package %{nil}' -D '_unpackaged_files_terminate_build exit 0' xmldiff-0.6.8-1.fc6.src.rpm

Now, back to comparing xml files.

by Thomas at February 10, 2012 12:56 PM