Skip to main content

Ralsina.Me — Roberto Alsina's website

Posts about linux

The Minimal Server

I was a sysad­min for a long time. I did that for mon­ey, so I nev­er re­al­ly want­ed to spend time do­ing the same thing in my own time, which lead to a se­vere case of cob­bler's chil­dren walk­ing bare­foot in my pri­vate serv­er.

So, to­day at lunch, I de­cid­ed to clean up my garbage. So this is what I end­ed up with, which is the min­i­mal serv­er that is good enough to be gen­er­al­ly use­ful for me.

Hosting

This is a cheap VPS pro­vid­ed by the nice folks at burst.net who are not giv­ing me any­thing to speak nice things about their ser­vice. How­ev­er, I will do it any­way:

  • Crazy cheap ($5.50 but I have a 20% dis­­­count for life)

  • Good amount of mon­th­­ly band­width

  • Lots of disk space

  • Good up­­­time

  • Fast net­­work

  • Very cheap

  • De­­cent per­­for­­mance

Distribution

I had Cen­tOS 5 in­stalled, and it stays. If burst ev­er starts of­fer­ing Ubun­tu Pre­cise, I may switch. Or, since this work­s, I may not.

What's good about Cen­tOS? It's sta­ble and bor­ing.

What's bad about Cen­tOS? It's too bor­ing. Lots of cool stuff just is­n't pack­aged.

Web Server

I need to serve a bunch of do­main­s, but I have a pe­cu­liar­i­ty: they are all stat­ic sites. I wan­t:

  • Low re­­source us­age

  • De­­cent per­­for­­mance (that most­­ly in­­­volves sup­­port­ing ranges and con­­tent ne­­go­ti­a­­tion)

  • Sta­ble

  • Sup­­port di­rec­­to­ry in­­dex­es

  • Easy con­­fig­u­ra­­tion

  • Vir­­tu­al do­­mains by name

Al­most any serv­er works well for this. Even Apache, ex­cept for the easy con­fig­u­ra­tion bit. I end­ed up with gatling be­cause it fits those cri­te­ria fair­ly well.

  • It us­es about 1.4MB of RAM , which is al­ways nice in a VPS

  • It's pret­­ty fast

  • Has not crashed in 2 hours?

  • Sup­­ports in­­dex­es

  • Here's the con­­fig­u­ra­­tion: "-c /s­rv/www -P 2M -d -v -p 80 -F -S" (yes, there is no con­­fig file at al­l)

  • Vir­­tu­al do­­mains are just fold­ers and sym­links in­­­side /s­rv/www which is the eas­i­est pos­sil­ble way to do it.

  • It sup­­ports re­­verse prox­­y­ing for when I want to try a python web app I am work­ing on.

Mail Server

No, I don't want a mail serv­er. I have gmail and/or a re­al mail serv­er for that. I want to get the mails from cron. For this, I used ssmtp and an ex­tra gmail ac­coun­t. It work­s, and here's the whole con­fig:

root=roberto.alsina@gmail.com
mailhub=smtp.gmail.com:587
UseTLS=YES
UseSTARTTLS=YES
AuthMethod=LOGIN
AuthUser=roberto.alsina.3@gmail.com
AuthPass=notputtingthetrueoneheredude

The best I can say about this con­fig­u­ra­tion is that it work­s, and does­n't in­volve run­ning a dae­mon.

Misc

For when I need to be in two places at the same time: Open­VPN rules, and there is no ar­gu­men­t. I have a squid run­ning oc­ca­sion­al­ly, and there is a Quas­sel core for IRC stuff. I in­stalled mosh to make ssh less painful, rsync han­dles file de­ploy­ment and back­up stor­age, cron sched­ules stuff, and that's it.

Status

Plen­ty of free RAM and CPU (yes, that's the full process list):

[root@burst1 ~]# ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.1   2156   664 ?        Ss   22:01   0:00 init [3]
root      1135  0.0  0.1   2260   576 ?        S<s  22:01   0:00 /sbin/udevd -d
root      1518  0.0  0.1   1812   572 ?        Ss   22:01   0:00 syslogd -m 0
root      1594  0.0  0.1   7240  1032 ?        Ss   22:01   0:00 /usr/sbin/sshd
root      1602  0.0  0.2   4492  1112 ?        Ss   22:01   0:00 crond
root      1630  0.0  0.1   5684   716 ?        Ss   22:01   0:00 /usr/sbin/saslauthd -m /var/run/saslauthd -a pam -n 2
root      1631  0.0  0.0   5684   444 ?        S    22:01   0:00 /usr/sbin/saslauthd -m /var/run/saslauthd -a pam -n 2
root      1636  0.0  0.2   3852  1372 ?        S    22:01   0:01 /opt/diet/bin/gatling -c /srv/www -P 2M -d -v -p 80 -F -S
root      1677  0.0  0.2   4284  1232 ?        Ss   22:02   0:00 SCREEN /root/quasselcore-static-0.7.1
root      1678  0.0  2.1  36688 11148 pts/0    Ssl+ 22:02   0:03 /root/quasselcore-static-0.7.1
root      3228  1.0  0.7  12916  4196 ?        Ss   23:28   0:13 mosh-server new -s -c 8
root      3229  0.0  0.3   3848  1588 pts/2    Ss   23:28   0:00 -bash
root      3275  0.0  0.1   2532   908 pts/2    R+   23:48   0:00 ps aux
[root@burst1 ~]# w
 23:49:03 up  1:47,  1 user,  load average: 0.00, 0.01, 0.00
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU WHAT
root     pts/2    186.153.52.253   23:28    0.00s  0.01s  0.00s w
[root@burst1 ~]# free
             total       used       free     shared    buffers     cached
Mem:        524800      49100     475700          0          0          0
-/+ buffers/cache:      49100     475700
Swap:            0          0          0

All things con­sid­ered, fair­ly hap­py with the re­sult.

Ubuntu One APIs by Example (part 1)

One of the nice things about work­ing at Canon­i­cal is that we pro­duce open source soft­ware. I, specif­i­cal­ly, work in the team that does the desk­top clients for Ubun­tu One which is a re­al­ly cool job, and a re­al­ly cool piece of soft­ware. How­ev­er, one thing not enough peo­ple know, is that we of­fer damn nice APIs for de­vel­op­er­s. We have to, since all our client code is open source, so we need those APIs for our­selves.

So, here is a small tu­to­ri­al about us­ing some of those APIs. I did it us­ing Python and PyQt for sev­er­al rea­son­s:

  • Both are great tools for pro­­to­­typ­ing

  • Both have good sup­­port for the re­quired stuff (D­Bus, HTTP, OAu­th)

  • It's what I know and en­joy. Since I did this code on a sun­­day, I am not go­ing to use oth­­er things.

Hav­ing said that, there is noth­ing python-spe­cif­ic or Qt-spe­cif­ic in the code. Where I do a HTTP re­quest us­ing Qt­Net­work, you are free to use lib­soup, or what­ev­er.

So, on to the nuts and bolt­s. The main pieces of Ubun­tu One, from a in­fra­struc­ture per­spec­tive, are Ubun­tu SSO Clien­t, that han­dles us­er reg­is­tra­tion and login, and Sync­Dae­mon, which han­dles file syn­chro­niza­tion.

To in­ter­act with them, on Lin­ux, they of­fer DBus in­ter­faces. So, for ex­am­ple, this is a frag­ment of code show­ing a way to get the Ubun­tu One cre­den­tials (this would nor­mal­ly be part of an ob­jec­t's __init__):

# Get the session bus
bus = dbus.SessionBus()

:
:
:

# Get the credentials proxy and interface
self.creds_proxy = bus.get_object("com.ubuntuone.Credentials",
                        "/credentials",
                        follow_name_owner_changes=True)

# Connect to signals so you get a call when something
# credential-related happens
self.creds_iface = dbus.Interface(self.creds_proxy,
    "com.ubuntuone.CredentialsManagement")
self.creds_proxy.connect_to_signal('CredentialsFound',
    self.creds_found)
self.creds_proxy.connect_to_signal('CredentialsNotFound',
    self.creds_not_found)
self.creds_proxy.connect_to_signal('CredentialsError',
    self.creds_error)

# Call for credentials
self._credentials = None
self.get_credentials()

You may have no­ticed that get_­cre­den­tials does­n't ac­tu­al­ly re­turn the cre­den­tial­s. What it does is, it tells Sync­Dae­mon to fetch the cre­den­tial­s, and then, when/if they are there, one of the sig­nals will be emit­ted, and one of the con­nect­ed meth­ods will be called. This is nice, be­cause it means you don't have to wor­ry about your app block­ing while Sync­Dae­mon is do­ing all this.

But what's in those meth­ods we used? Not much, re­al­ly!

def get_credentials(self):
    # Do we have them already? If not, get'em
    if not self._credentials:
        self.creds_proxy.find_credentials()
    # Return what we've got, could be None
    return self._credentials

def creds_found(self, data):
    # Received credentials, save them.
    print "creds_found", data
    self._credentials = data
    # Don't worry about get_quota yet ;-)
    if not self._quota_info:
        self.get_quota()

def creds_not_found(self, data):
    # No credentials, remove old ones.
    print "creds_not_found", data
    self._credentials = None

def creds_error(self, data):
    # No credentials, remove old ones.
    print "creds_error", data
    self._credentials = None

So, ba­si­cal­ly, self­._­cre­den­tials will hold a set of cre­den­tial­s, or None. Con­grat­u­la­tion­s, we are now logged in­to Ubun­tu One, so to speak.

So, let's do some­thing use­ful! How about ask­ing for how much free space there is in the ac­coun­t? For that, we can't use the lo­cal APIs, we have to con­nect to the server­s, who are, af­ter al­l, the ones who de­cide if you are over quo­ta or not.

Ac­cess is con­trolled via OAuth. So, to ac­cess the API, we need to sign our re­quest­s. Here is how it's done. It's not par­tic­u­lar­ly en­light­en­ing, and I did not write it, I just use it:

def sign_uri(self, uri, parameters=None):
    # Without credentials, return unsigned URL
    if not self._credentials:
        return uri
    if isinstance(uri, unicode):
        uri = bytes(iri2uri(uri))
    print "uri:", uri
    method = "GET"
    credentials = self._credentials
    consumer = oauth.OAuthConsumer(credentials["consumer_key"],
                                   credentials["consumer_secret"])
    token = oauth.OAuthToken(credentials["token"],
                             credentials["token_secret"])
    if not parameters:
        _, _, _, _, query, _ = urlparse(uri)
        parameters = dict(cgi.parse_qsl(query))
    request = oauth.OAuthRequest.from_consumer_and_token(
                                        http_url=uri,
                                        http_method=method,
                                        parameters=parameters,
                                        oauth_consumer=consumer,
                                        token=token)
    sig_method = oauth.OAuthSignatureMethod_HMAC_SHA1()
    request.sign_request(sig_method, consumer, token)
    print "SIGNED:", repr(request.to_url())
    return request.to_url()

And how do we ask for the quo­ta us­age? By ac­cess­ing the http­s://one.ubun­tu.­com/api/quo­ta/ en­try point with the prop­er au­tho­riza­tion, we would get a JSON dic­tio­nary with to­tal and used space. So, here's a sim­ple way to do it:

    # This is on __init__
    self.nam = QtNetwork.QNetworkAccessManager(self,
        finished=self.reply_finished)

:
:
:

def get_quota(self):
    """Launch quota info request."""
    uri = self.sign_uri(QUOTA_API)
    url = QtCore.QUrl()
    url.setEncodedUrl(uri)
    self.nam.get(QtNetwork.QNetworkRequest(url))

Again, see how get_quo­ta does­n't re­turn the quo­ta? What hap­pens is that get_quo­ta will launch a HTTP re­quest to the Ubun­tu One server­s, which will, even­tu­al­ly, re­ply with the da­ta. You don't want your app to block while you do that. So, QNet­workAc­cess­Man­ag­er will call self­.re­ply_fin­ished when it gets the re­spon­se:

def reply_finished(self, reply):
    if unicode(reply.url().path()) == u'/api/quota/':
        # Handle quota responses
        self._quota_info = json.loads(unicode(reply.readAll()))
        print "Got quota: ", self._quota_info
        # Again, don't worry about update_menu yet ;-)
        self.update_menu()

What else would be nice to have? How about get­ting a call when­ev­er the sta­tus of sync­dae­mon changes? For ex­am­ple, when sync is up to date, or when you get dis­con­nect­ed? Again, those are DBus sig­nals we are con­nect­ing in our __init__:

self.status_proxy = bus.get_object(
    'com.ubuntuone.SyncDaemon', '/status')
self.status_iface = dbus.Interface(self.status_proxy,
    dbus_interface='com.ubuntuone.SyncDaemon.Status')
self.status_iface.connect_to_signal(
    'StatusChanged', self.status_changed)

# Get the status as of right now
self._last_status = self.process_status(
    self.status_proxy.current_status())

And what's sta­tus_changed?

def status_changed(self, status):
    print "New status:", status
    self._last_status = self.process_status(status)
    self.update_menu()

The pro­cess_s­ta­tus func­tion is bor­ing code to con­vert the in­fo from sync­dae­mon's sta­tus in­to a hu­man-read­able thing like "Sync is up­-­to-­date". So we store that in self­._last_s­ta­tus and up­date the menu.

What menu? Well, a QSys­tem­Tray­I­con's con­text menu! What you have read are the main pieces you need to cre­ate some­thing use­ful: a Ubun­tu One tray app you can use in KDE, XFCE or open­box. Or, if you are on uni­ty and in­stall sni-qt, a Ubun­tu One app in­di­ca­tor!

http://ubuntuone.com/7iXTbysoMM9PIUS9Ai4TNn

My Ubun­tu One in­di­ca­tor in ac­tion.

You can find the source code for the whole ex­am­ple app at my u1-­toys project in launch­pad and here is the full source code (miss­ing some icon re­sources, just get the re­po)

Com­ing soon(ish), more ex­am­ple app­s, and cool things to do with our APIs!

$HOME is where .bashrc is

I have a con­fes­sion to make. For the last year or so, my main op­er­at­ing sys­tem has been Win­dows 7. Yes, I know, it may come as a shock to some, spe­cial­ly if you have read this which is my post that had most hits in a day ev­er.

How did that hap­pen? What hap­pened to me? What was I think­ing? It's a bor­ing and un­in­ter­est­ing sto­ry.

I joined Canon­i­cal. My old note­book would­n't cut it. My new one would not take Ubun­tu with­out a fight. I said "hey, I will live in a VM!". The VM was dead­ly slow. I had to de­vel­op win­dows soft­ware (yes). Some stuff would not work right on the VM. And slow­ly, things just start­ed pil­ing up in the bare-met­al OS, which was, yes Win­dows 7 Home Pre­mi­um.

As a whole, Win­dows 7 is not hor­ri­ble. Most things work well. What it is, is a desert for a de­vel­op­er. Sure, you can get a plant to grow there, but you have to put a lot of ef­fort in­to it.

So, to­day I in­stalled Kubun­tu Oneir­ic (ab­so­lute­ly no prob­lem now!), gath­ered all the da­ta from the old note­book, the VM, the win­dows in­stal­la­tion, delet­ed win­dows, and moved in­to Lin­ux again, and made Win­dows the VM.

I missed it.

Android on x86: report

Since I ex­pect An­droid on tablets to be a big thing in 2010, I am ex­per­i­ment­ing with the clos­est thing I can get: An­droid in my eee 701 Surf 4G:

SDC14690

I got the test­ing An­droid 2.0 im­age from http://an­droid-x86.org. I had the 1.6 "stable" one but it was... well, it worked aw­ful (half the key com­bos or menu op­tions caused it to crash, re­boot or oth­er­wise au­to­com­bust).

So... how is it work­ing? Slow, but it has po­ten­tial!

The bad:

  • It boots quite fast... but my tricked full Arch Lin­ux in­­stall boots faster.

  • It works sloooooow, you can see in­­di­vid­u­al let­ters when you type in the search gad­get. I read this is a tem­po­rary prob­lem, though.

  • I am get­t­ing a "cas­­trat­ed" ex­pe­ri­ence be­­cause the open an­­droid app stores are not as well stocked as the of­­fi­­cial an­­droid mar­ket­­place (and come on, why the heck can't I get free apps from there???)

    I see ob­vi­ous holes in the app land­s­cape that I sup­­pose are well cov­­ered in the mar­ket (like, is there a Ra­­dio­­Tray re­­place­­men­t?)

    No text ed­i­­tor?

    No semi-de­­cent word pro­ces­­sor? Not even one that gen­er­ates HT­M­L?

  • The web brows­er is pa­­thet­ic. It may be nice for a phone, but for a "re­al" sys­tem? It's aw­­ful. You get the mo­­bile ver­­sions of all sites (ob­vi­ous­­ly) and many don't let you switch to the re­al ones! (even google does that, for Google Read­­er), and of course, no flash.

  • The email app is ter­ri­ble. You can't not-­­top-­­post!!!! "In-Re­­ply-­­To" is of­f-spec!

  • The WiFi set­t­ings are way too hid­­den. They should pop if you click on the wifi icon.

The good:

  • It shuts down in­­­cred­i­bly fast.

  • Some apps are quite nice, spe­­cial­­ly the Aldiko book read­­er is awe­­some (and I can share the ePub books with fbRead­­er on the arch lin­ux side.

  • The in­­­clud­ed SSH client has great ideas.

  • I love the "all your da­­ta is in the SD" ap­proach. I do the same thing with Lin­ux. In fac­t, I have the same ex­act da­­ta or­­ga­ni­za­­­tion now on both OSs :-)

  • The home screen with the slid­ing app draw­er: nice

  • The "grab­bable" sys­tem no­ti­­fi­­ca­­tions on the top bar: very nice

  • The "use the menu key to get the menu" thing? ge­nius ;-)

  • The "ev­ery­thing fullscreen all the time", thing? works on this screen.

  • App in­­stal­la­­tion is a solved prob­lem here.

  • I know I will be able to get Qt work­ing na­­tive... can't wait!

I am not sold yet, Arch is just so much faster right now, and it can do so much more, but...

  • I am get­t­ing a touch­screen for it, so I can ex­pe­ri­ence it more the way it's meant to be ex­pe­ri­enced.

  • I am us­ing it a lot to read at night in bed (Just fin­ished Mak­ers, read it, it's cool!).

  • I am us­ing it for ca­­su­al mail read­­ing (I refuse to re­­ply with that bro­ken ap­p).

  • It's a pret­­ty nice alarm clock, so it's be­­com­ing my bed­­side OS.

I'll write an­oth­er re­port once I have the touch screen or a new (hope­ful­ly faster!) ver­sion run­ning.

The day we saw the dinosaur (an Ada Lovelace Day story)

To­day, March 24th is Ada Lovelace day, a day of blog­ging to cel­e­brate the achieve­ments of wom­en in tech­nol­o­gy and sci­ence.. I am tak­ing the lib­er­ty to tag this as python so it ap­pears in the right plan­et­s, but that's just to pro­mote Ada Lovelace day. Sor­ry 'bout that.

I will write about the on­ly per­son who ev­er taught me pro­gram­ming, Clau­di­a. I was young, so the earth was still luke­war­m, the day we saw the di­nosaur.

I was just a green sopho­more in the School of Chem­i­cal En­gi­neer­ing where, para­dox­i­cal­ly I would nev­er take a chem­istry class, be­ing an ap­plied math stu­dent and all that, and at the time "per­son­al com­put­er­s" were a nov­el­ty, a toy of the up­per mid­dle class.

We had spent the first two months of the se­mes­ter learn­ing how to pro­gram the ob­vi­ous way: writ­ing as­sem­bler for a fic­tion­al ma­chine on pa­per by hand, when Clau­dia broke the news, we were go­ing to see a re­al com­put­er.

No, not a PC, not even an XT, but a re­al com­put­er, the one re­al com­put­er in all the uni­ver­si­ty, and you could hear the type switch­ing to bold as she spoke about it. Sad­ly it was not as re­al as the one at the re­search fa­cil­i­ty (A Mini­VAX!) but it was a re­al enough PDP.

We would not be al­lowed to ac­tu­al­ly use it un­til the fol­low­ing year, but ... well, it was still some­thing spe­cial.

I had been programming for years, even for a year before I saw my first (seriosuly not real) computer, I had followed BASIC programs in my head for days, imagining the space invaders float on the screen of my mind, and stepped into writing machine code inside REM statements in my Timex Sinclair 1000 onto the luxury of a C64, but never noone had taught me anything.

Our small class (maybe 10 stu­dents) spent end­less hours do­ing things like tra­verse a ma­trix, first by rows, thn by column­s, then in a spi­ral from the top-left, writ­ing pro­grams that fol­lowed our end­less source of al­go­rithm­s, the nu­mer­i­cal so­lu­tions guide.

First as­sem­bler, then For­tran, we learned.

She was my Mr. Miyag­i, I was a het­ero­sex­u­al Ralph Mac­chio, and I fig­ured out the most im­por­tant thing about pro­gram­ming: I was aw­ful at it.

Over the next 20 years that sit­u­a­tion has been slow­ly im­prov­ing, but I nev­er again had some­one teach me pro­gram­ming. Clau­dia had al­ready taught me ev­ery­thing I need­ed to know, that code can al­ways im­prove, that there's more than one way to skin a cat.

That the di­nosaur was re­al and that some day soon my com­put­er would be faster and nicer than the di­nosaur was then, and that pro­gram­ming was cool, and that if I could find a way to draw a poly­no­mi­al graph hor­i­zon­tal­ly on a print­er with­out ev­er hav­ing the whole graph in mem­o­ry (it did­n't fit), those fu­ture com­put­ers would do awe­some things, and that I was one of the many who would help bring that to re­al­i­ty.

That talk­ing about code was fun in it­self, that you could make a mod­est liv­ing and be hap­py about it, that you could in any case make jig­saw puz­zles in your spare time and keep on teach­ing or what­ev­er.

And lat­er the di­nosaur's bones were scav­enged in­to a line of racks hold­ing router­s, and its glass ter­mi­nals are de­stroyed, and the gold in its teeth was stolen and the rare bus ca­bles sol­d, and its cir­cuits scrapped, but I saw the di­nosaur alive, and Clau­dia taught me how to make it jump, and for that, I will al­ways be grate­ful.