<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
    xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:wfw="http://wellformedweb.org/CommentAPI/"
    xmlns:dc="http://purl.org/dc/elements/1.1/"
    xmlns:atom="http://www.w3.org/2005/Atom"
    xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
    xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
>
    <channel>
        <title></title>
        <atom:link href="http://www.silassewell.com/rss2.xml" rel="self" type="application/rss+xml" />
        <link>http://www.silassewell.com</link>
        <description>Infrastructure Development</description>
        <lastBuildDate>Sat, 08 Jan 2011 00:00:00 GMT</lastBuildDate>
        <generator>http://www.silassewell.com/</generator>
        <language>en</language>
        <sy:updatePeriod>hourly</sy:updatePeriod>
        <sy:updateFrequency>1</sy:updateFrequency>

        <item>
            <title>Setup Gitolite on Ubuntu (Maverick)</title>
            <link>http://www.silassewell.com/blog/2011/01/08/setup-gitolite-on-ubuntu/</link>
            <pubDate>Sat, 08 Jan 2011 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[Git]]></category><category><![CDATA[Gitolite]]></category><category><![CDATA[Linux]]></category><category><![CDATA[Ubuntu]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2011/01/08/setup-gitolite-on-ubuntu/</guid>
            <description><![CDATA[<p>Below is a quick guide to installing <a href="https://github.com/sitaramc/gitolite">Gitolite</a> on Ubuntu.</p>

<ol>
<li><p>Create an SSH public/private key pair</p>

<pre><code class="prettyprint">[user@client ~]$ ssh keygen -t rsa
</code></pre></li>
<li><p>Upload the public key to the server</p>

<pre><code class="prettyprint">[user@client ~]$ scp ~/.ssh/id_rsa.pub user@server.example.org:/tmp/user.pub
</code></pre></li>
<li><p>SSH to the server and become <code class="prettyprint">root</code></p>

<pre><code class="prettyprint">[user@client ~]$ ssh user@server.example.org
user@server:~$ sudo su -
</code></pre></li>
<li><p>Install <code class="prettyprint">gitolite</code></p>

<pre><code class="prettyprint">root@server:~# apt-get install gitolite
</code></pre></li>
<li><p>Switch to the <code class="prettyprint">gitolite</code> user</p>

<pre><code class="prettyprint">root@server:~# su - gitolite
</code></pre></li>
<li><p>Run the Gitolite setup script</p>

<pre><code class="prettyprint">gitolite@server:~$ gl-setup /tmp/user.pub
</code></pre></li>
<li><p>From your client computer clone the <code class="prettyprint">gitolite-admin</code> repository</p>

<pre><code class="prettyprint">[user@client ~]$ git clone gitolite@server.example.org:gitolite-admin
Cloning into gitolite-admin...
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (6/6), done.
</code></pre></li>
<li><p>Switch to the <code class="prettyprint">gitolite-admin</code> directory</p>

<pre><code class="prettyprint">[user@client ~]$ cd gitolite-admin
</code></pre></li>
<li><p>Create a <code class="prettyprint">test</code> repository</p>

<pre><code class="prettyprint">[user@client gitolite-admin]$ vim conf/gitolite.conf
[user@client gitolite-admin]$ git commit -a -m "Add test repository"
[user@client gitolite-admin]$ git a
[master 507045a] Add test repository
 1 files changed, 3 insertions(+), 0 deletions(-)
[user@client gitolite-admin]$ git push
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 376 bytes, done.
Total 4 (delta 1), reused 0 (delta 0)
remote: Already on 'master'
remote: creating test...
remote: Initialized empty Git repository in /var/lib/gitolite/repositories/test.git/
To gitolite@server.example.org:gitolite-admin
   87cc470..507045a  master -&gt; master
</code></pre></li>
<li><p>Clone the <code class="prettyprint">test</code> repository</p>

<pre><code class="prettyprint">[user@client ~]$ git clone gitolite@server.example.org:test
Cloning into test...
warning: You appear to have cloned an empty repository.
</code></pre></li>
<li><p>Add a <code class="prettyprint">README</code> file to the <code class="prettyprint">test</code> repository</p>

<pre><code class="prettyprint">[user@client test]$ echo "Test Repo" &gt; README
[user@client test]$ git commit -a -m "Initial commit"
[master (root-commit) 4a49ee0] Initial commit
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 README
</code></pre></li>
<li><p>Push the changes to the server</p>

<pre><code class="prettyprint">[user@client test]$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 218 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To gitolite@server.example.org:test
 * [new branch]      master -&gt; master
</code></pre></li>
</ol>

<p>Check out the Gitolite <a href="https://github.com/sitaramc/gitolite/wiki/">wiki</a> for more documentation.</p>]]></description>
        </item>

        <item>
            <title>txsrv: Message-based Twisted Services</title>
            <link>http://www.silassewell.com/blog/2010/09/12/txsrv-message-based-twisted-services/</link>
            <pubDate>Sun, 12 Sep 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[AMQP]]></category><category><![CDATA[Fedora]]></category><category><![CDATA[Python]]></category><category><![CDATA[Twisted]]></category><category><![CDATA[txsrv]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/09/12/txsrv-message-based-twisted-services/</guid>
            <description><![CDATA[<p>I've started work on <a href="http://github.com/silas/txsrv" title="txsrv">txsrv</a>, a Python library that aims to make
developing message-based services in Twisted easy.</p>

<p>The code is still pretty rough, but might be of interest to someone hacking on
AMQP-based Twisted services.</p>

<p>Sample Usage</p>

<ol>
<li><p>Create a new service and change to the project directory.</p>

<pre><code class="prettyprint">$ txsrv create mytest
$ cd mytest
</code></pre></li>
<li><p>Edit the <code class="prettyprint">mytest.conf</code> file so that the <code class="prettyprint">spec_file</code> option is valid.</p>

<pre><code class="prettyprint">[connection:amqp]
type = amqp
host = localhost
port = 5672
vhost = /
user = guest
password = guest
spec_file = /usr/share/amqp/amqp.0-8.xml

[handler:hello]
connection = amqp
exchange = hello
routing_key = default
</code></pre></li>
<li><p>Edit the <code class="prettyprint">mytest.py</code> file so that it prints the message body twice.</p>

<pre><code class="prettyprint">import txsrv

class Service(txsrv.Service):
    @txsrv.handler('hello')
    def hello(self, message):
        print message.body * 2

class ServiceMaker(txsrv.ServiceMaker):
    tapname = 'mytest'
    description = 'A mytest txsrv example.'
    service_type = Service
</code></pre></li>
<li><p>Start the <code class="prettyprint">mytest</code> service and send a message to the <code class="prettyprint">hello</code> exchange.</p>

<pre><code class="prettyprint">$ twistd -n mytest -c mytest.conf
2010-09-12 00:41:10-0400 [-] Log opened.
2010-09-12 00:41:10-0400 [-] twistd 10.1.0 (/usr/bin/python 2.6.4) starting up.
2010-09-12 00:41:10-0400 [-] reactor class: twisted.internet.selectreactor.SelectReactor.
2010-09-12 00:41:10-0400 [-] Starting factory &lt;txsrv.protocol.amqp.AmqpFactory instance at 0x2cce950&gt;
2010-09-12 00:41:10-0400 [AmqpProtocol,client] hellohello
</code></pre></li>
</ol>]]></description>
        </item>

        <item>
            <title>Go Programming Language: Hello World (Fedora 13)</title>
            <link>http://www.silassewell.com/blog/2010/07/28/go-programming-language-hello-world-fedora-13/</link>
            <pubDate>Wed, 28 Jul 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[Fedora]]></category><category><![CDATA[Go]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/07/28/go-programming-language-hello-world-fedora-13/</guid>
            <description><![CDATA[<p>If you're interested in trying the <a href="http://golang.org/">Go Programming Language</a> I've created
an RPM for Fedora 13 to get you started quick (this package is in no way
suitable for submission to Fedora).</p>

<ol>
<li><p>Download the <a href="http://silas.fedorapeople.org/packages/go/go-0.0.0-0.1.release.2010.07.14.fc13.x86_64.rpm">x86_64</a> (or <a href="http://silas.fedorapeople.org/packages/go/go-0.0.0-0.1.release.2010.07.14.fc13.i686.rpm">i386</a>) RPM.</p></li>
<li><p>Install the Go package using yum.</p>

<pre><code class="prettyprint">sudo yum localinstall --nogpgcheck go-0.0.0*.rpm
</code></pre></li>
<li><p>Open a new shell.</p></li>
<li><p>Create a file named <code class="prettyprint">hello.go</code> and enter the following code:</p>

<pre><code class="prettyprint">package main

import "fmt"

func main() {
  fmt.Printf("Hello World!")
}
</code></pre></li>
<li><p>Compile, link and run (replace <code class="prettyprint">6</code> with <code class="prettyprint">8</code> if you're using i386).</p>

<pre><code class="prettyprint">$ 6g hello.go
$ 6l hello.6
$ ./6.out
</code></pre></li>
</ol>

<p>You can view the latest RPM source on <a href="http://github.com/silas/rpms/tree/master/go/">GitHub</a>.</p>

<p><em>Update</em>: It looks like someone has already created a much better
<a href="https://bugzilla.redhat.com/show_bug.cgi?id=610934">package</a>.</p>]]></description>
        </item>

        <item>
            <title>GNU Screen Profiles</title>
            <link>http://www.silassewell.com/blog/2010/07/14/gnu-screen-profiles/</link>
            <pubDate>Wed, 14 Jul 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[Fedora]]></category><category><![CDATA[GNU Screen]]></category><category><![CDATA[Screen]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/07/14/gnu-screen-profiles/</guid>
            <description><![CDATA[<p>If you're a regular <a href="http://www.gnu.org/software/screen/" title="GNU Screen">GNU Screen</a> user might find this hack for creating
profiles useful.</p>

<ol>
<li><p>Create a <code class="prettyprint">.screen</code> directory in your home directory.</p>

<pre><code class="prettyprint">mkdir "$HOME/.screen"
</code></pre></li>
<li><p>Add the following to your <code class="prettyprint">.bashrc</code> or <code class="prettyprint">.bash_profile</code>.</p>

<pre><code class="prettyprint">sp() {
  if [[ -f "$HOME/.screen/$1" ]]; then
    screen -c "$HOME/.screen/$1"
  else
    echo "Unknown screen profile '$1'."
  fi  
}
</code></pre></li>
<li><p>Create a file in the <code class="prettyprint">~/.screen</code> directory with whatever profile name you
 would like to use (below is a sample profile named <code class="prettyprint">tyrion</code>).</p>

<p>You should copy the first line into each profile as it loads your default
 GNU Screen settings.</p>

<pre><code class="prettyprint">source "$HOME/.screenrc"

chdir "$HOME/src/tyrion/src"
screen -t code  0

chdir "$HOME/src/tyrion"
screen -t build  1

chdir "$HOME/src/tyrion/tests"
screen -t tests  2

chdir "$HOME/src/tyrion"
</code></pre></li>
<li><p>Reload your shell and test your profile (replace <code class="prettyprint">tyrion</code> with whatever
 name you picked).</p>

<pre><code class="prettyprint">[silas@example ~]$ sp tyrion
</code></pre></li>
</ol>]]></description>
        </item>

        <item>
            <title>Introduction to Tyrion</title>
            <link>http://www.silassewell.com/blog/2010/07/07/introduction-to-tyrion/</link>
            <pubDate>Wed, 07 Jul 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[C++]]></category><category><![CDATA[Fedora]]></category><category><![CDATA[Func]]></category><category><![CDATA[txtyrion]]></category><category><![CDATA[Tyrion]]></category><category><![CDATA[TyrionHub]]></category><category><![CDATA[XMPP]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/07/07/introduction-to-tyrion/</guid>
            <description><![CDATA[<p>Today I wanted to introduce Tyrion to the Fedora Planet and anyone who happens
to read my blog.</p>

<p>Tyrion is in short a lightweight <a href="https://fedorahosted.org/func/">Func</a> replacement.</p>

<h3>Why Tyrion?</h3>

<p>I created Tyrion because Func didn't meet some of my needs, specifically the
points outlined below.</p>

<p><strong>(1) Asynchronous</strong></p>

<p>Tyrion was built using a protocol which is inherently asynchronous. This has
lead to lower latency operations and better scalability.</p>

<p>That isn't to say Func couldn't be updated to be asynchronous (using the Twisted
XML-RPC libraries for example), but I think current toolsets highly favor
protocols which were designed from the beginning to be asynchronous.</p>

<p><strong>(2) Language Agnostic</strong></p>

<p>From a technical perspective Func is also language agnostic (it uses XML-RPC as
a transport protocol) and although you could write a client or server in any
language, from a pragmatic standpoint you're stuck writing services in Python.</p>

<p>On the other hand Tyrion is written in C++ and each service is a simple
executable.  This lends itself nicely to writing services in whatever language
is most appropriate.</p>

<p><strong>(3) Low memory footprint</strong></p>

<p>Func is written in Python and as such suffers from a dynamic language's higher
memory usage.</p>

<p>For example, the following Python application uses ~4.2MB memory on my Fedora 13
box.</p>

<pre><code class="prettyprint">#!/usr/bin/env python

import time

time.sleep(60)
</code></pre>

<p>While the complete <code class="prettyprint">tyrion-node</code> application uses ~4.5MB.</p>

<p>For many systems administrators the difference between Func and <code class="prettyprint">tyrion-node</code>'s
memory usage will be negligible, but if you running an infrastructure with
several hundred or several thousand hosts the resource difference can be
enormous.</p>

<p>A lower memory footprint is also advantageous to companies who heavily utilize
virtualization. If you have 5 servers and you slice those up into 4 virtual
machines each, you've just jumped from 5 to 20 daemons. Lets say Func uses 15MB
memory, that's a 60MB to 300MB jump compared to <code class="prettyprint">tyrion-node</code>'s 22.5MB to 90MB.</p>

<p><strong>(4) Permissions</strong></p>

<p>The protocol that Tyrion uses has built-in support for users. This allows Tyrion
to support user specific permissions on a service level and opens up some really
cool possibility, such as exposing services to partially trusted users.</p>

<p>In addition because Tyrion uses a process model to run each service, a
configuration setting can be defined to specify under which user and group a
service is run.</p>

<p><strong>(5) Cloud</strong></p>

<p>This is a somewhat stupid bullet, but it does have some credibility. Func was
created to rely on a hostname/certificate combindation and the assumption that
we could communicate to a managed host on a defined port. This setup works great
when you have full control over your network.</p>

<p>Unfortunately many of us use external resources (AWS, Linode, Slicehost, etc...)
where some or much of the network and infrastructure configuration is out of our
control.</p>

<p>Tyrion was built on the <a href="http://en.wikipedia.org/wiki/Xmpp">XMPP</a> protocol, this means that Tyrion connects
to a XMPP server and just listens for events.</p>

<p>With XMPP we also get authentication, an encrypted transport, some
decentralization, federation, a solid selection of open source and scalable
servers and clients for pretty much every language.</p>

<p><strong>(6) Hot Reloads</strong></p>

<p>The ability to update configuration settings and install services without a
daemon restart.</p>

<h3>Overview</h3>

<p>This will briefly overview how Tyrion works.</p>

<p>The Tyrion package has two primary parts, the <code class="prettyprint">tyrion</code> client and the
<code class="prettyprint">tyrion-node</code>.</p>

<p><code class="prettyprint">tyrion-node</code> is daemon which runs on each managed server. It boots with the
host, connects to an XMPP server and listens for service requests.</p>

<p><strong>tyrion-node Configuration</strong></p>

<p>Below is the general configuration settings for <code class="prettyprint">tyrion-node</code> which are located
in the <code class="prettyprint">node.conf</code> file:</p>

<pre><code class="prettyprint">[general]
acl_path = /etc/tyrion/acl.conf                 ; ACL configuration file
log_path = /var/log/tyrion/node.log             ; Logging path
log_level = info                                ; Logging level
service_path = /usr/share/tyrion/service        ; Service directory

[xmpp]
jid = test.node@example.org/tyrion              ; Tyrion node JID
password = test.node.pass                       ; Tyrion node password
;server = example.org                            ; Server address if different from JID domain
</code></pre>

<p>The <code class="prettyprint">node.conf</code> file also lets you define default values for installed services.</p>

<pre><code class="prettyprint">[service:org.tyrion.service.bash]
timeout = 300                                   ; Default service timeout (seconds)
timeout_lock = false                            ; Lock default timeout setting
user = mike                                     ; Default user to run service as
user_lock = false                               ; Lock default user setting
</code></pre>

<p>This tells Tyrion that the <code class="prettyprint">org.tyrion.service.bash</code> service should have a
default timeout of <code class="prettyprint">300</code> seconds and run as the user <code class="prettyprint">mike</code>. In this case
because we haven't locked the <code class="prettyprint">timeout</code> or <code class="prettyprint">user</code> option they can be overriden
by the requester.</p>

<p><strong>tyrion-node Service</strong></p>

<p>If you were to look in the <code class="prettyprint">service_path</code> directory you would see an executable
file named <code class="prettyprint">org.tyrion.service.bash</code>.</p>

<pre><code class="prettyprint">[silas@example.org]$ cat /usr/share/tyrion/service/org.tyrion.service.bash 
#!/usr/bin/env sh

/usr/bin/env bash
</code></pre>

<p>Obviously this service is a bit redundant and not all that interesting, but
serves as a good example of how a service works.</p>

<p><strong>tyrion Client</strong></p>

<p>First we'll cover the basics of the <code class="prettyprint">tyrion</code> client. Then we'll use that
information to make a basic service request and follow that request from the
client to the node and back again.</p>

<p><strong>tyrion Client Configuration</strong></p>

<p>First the <code class="prettyprint">client.conf</code> file:</p>

<pre><code class="prettyprint">[xmpp]
jid = test.client@example.org                   ; Tyrion node JID
password = test.client.pass                     ; Tyrion node password
;server = example.org                            ; Server address if different from JID domain

[profile:test]
jid = test.node@example.org/tyrion              ; Default destination JID
service = org.tyrion.service.bash               ; Default service type
timeout = 300                                   ; Default timeout
user = usertest                                 ; Default user
group = grouptest                               ; Default group
</code></pre>

<p>We can see that like the <code class="prettyprint">node.conf</code> file we have our XMPP options under the
<code class="prettyprint">xmpp</code> section. Below that we also have a default profile called <code class="prettyprint">test</code>. Similiar
to the service section in the <code class="prettyprint">node.conf</code> file this lets us setup some basic
defaults. Here we're defining a destination jid, service, timeout, user and
group.</p>

<p><strong>tyrion Client Options</strong></p>

<p>Additionally if we ran the help option on <code class="prettyprint">tyrion</code> we would see the following:</p>

<pre><code class="prettyprint">[silas@example.org]$ tyrion --help
Usage: tyrion [OPTION]...
Example: tyrion -c client.conf

Configuration options:
  -c, --config-file         the node configuration file
  -p, --profile             default service options

Service options:
  -j, --jid                 destination JID(s)
  -s, --service             service type
  -t, --timeout             max service run time
  -u, --user                run service as user
  -g, --group               run service as group

Misc options:
  --debug                   show debug information
</code></pre>

<p><strong>tyrion Client Usage</strong></p>

<p>So an example usage of <code class="prettyprint">tyrion</code> might be:</p>

<pre><code class="prettyprint">[silas@example.org]$ echo "echo test" | tyrion -c client.conf -p test
test.node@example.org/tyrion (0): test
</code></pre>

<p>Here we've run <code class="prettyprint">tyrion</code> with the <code class="prettyprint">client.conf</code> configuration file and the profile
<code class="prettyprint">test</code>.</p>

<p>We sent <code class="prettyprint">echo test</code> to the <code class="prettyprint">org.tyrion.service.bash</code> service and got the exit
code <code class="prettyprint">0</code> and the result <code class="prettyprint">test</code>.</p>

<p><strong>tyrion-node Handler</strong></p>

<p>From the other side <code class="prettyprint">tyrion-node</code> sees a request from <code class="prettyprint">test.client@example.org</code>
to use the service <code class="prettyprint">org.tyrion.service.bash</code>.</p>

<pre><code class="prettyprint">[org.tyrion.service.bash]
test.client@example.org = true

[org.tyrion.service.python]
test.client@example.org = true

[org.tyrion.service.ruby]
test.client@example.org = true
</code></pre>

<p>After validating that request against the above <code class="prettyprint">acl_path</code> file it runs the
<code class="prettyprint">/usr/share/tyrion/service/org.tyrion.service.bash</code> executable and pipes
<code class="prettyprint">echo test</code> to stdin.</p>

<p>When the service request completes or reaches the defined timeout it sends the
exit code, stdout and stderr back to the client.</p>

<h3>txtyrion</h3>

<p>The <code class="prettyprint">tyrion</code> client is really just for testing and one-off hacks. It not suppose
to be used in scripts or anything in production.</p>

<p>Because of this I created <code class="prettyprint">txtyrion</code>, a Twisted-based Tyrion client library.</p>

<p>A simple client application might look like this:</p>

<pre><code class="prettyprint">from twisted.internet import defer, reactor

import txtyrion

class ExampleClient(txtyrion.Client):

    def success(self, response):
        print '=' * 80
        print '     ID:', response.id
        print '    JID:', response.jid
        print '   Code:', response.code
        print 'Service:', response.service
        print ' Output:', response.output
        print '  Error:', response.error

    def error(self, error):
        print '=' * 80
        print 'Error:', error

    def done(self, x):
        print '=' * 80
        reactor.stop()

    def run(self):
        jid = 'test.node@example.org/tyrion'

        command = """
        sleep 1
        echo bash says hello stdout
        echo bash says hello stderr &gt;&amp;2
        false
        """
        d1 = self.request(jid, 'org.tyrion.service.bash', command)
        d1.addCallbacks(self.success, self.error)

        d2 = self.request(
            jid,
            'org.tyrion.service.python',
            'print "python says hello"',
        )
        d2.addCallbacks(self.success, self.error)

        dl = defer.DeferredList([d1, d2])
        dl.addCallback(self.done)

if __name__ == '__main__':
    client = ExampleClient(
        'test.client@example.org',
        'test.client.pass',
        debug=True,
    )
    reactor.run()
</code></pre>

<p>txtyrion also comes with a node library for creating custom Tyrion nodes
(see <a href="http://github.com/tidg/txtyrion/blob/master/examples/example_node.py">example</a>).</p>

<h3>TyrionHub</h3>

<p>It's my goal to keep Tyrion simple; to let people utilize it for as much or as
little as is appropriate for their situation.</p>

<p>That said I've created a separate project called TyrionHub which will provide a
Twisted-based system for managing nodes and a library of Python-based services
for systems automation.</p>

<p>The immediate goals for TyrionHub are:</p>

<ul>
<li>User authentication using <code class="prettyprint">twisted.cred</code></li>
<li>Node authentication using <code class="prettyprint">twisted.cred</code> and an integration script for
ejabbard </li>
<li>Node enrollment</li>
</ul>

<p>I'm currently building TyrionHub with the following technologies:</p>

<ul>
<li>Server: Twisted</li>
<li>Database: MongoDB (although this may change)</li>
<li>Web GUI: Google Closure Tools (JavaScript/Ajax/JSON)</li>
<li>Services: Python with JSON serialization (simple as possible, avoid
frameworks and all unnecessary libraries)</li>
</ul>

<h3>Status</h3>

<ul>
<li><a href="http://github.com/tidg/tyrion">Tyrion</a> - working and <a href="http://github.com/tidg/rpms/tree/master/tyrion/">packaged</a> (not in any repo),
although it could use some code reviews by people comfortable with C++</li>
<li><a href="http://github.com/tidg/tyrionhub">TyrionHub</a> - just getting started, lots of work to do</li>
<li><a href="http://github.com/tidg/txtyrion">txtyrion</a> - working with various tweaks here and there</li>
</ul>

<h3>Participation</h3>

<p>If anyone is interesting in participating in the development/testing process or
would like to be contacted when TyrionHub is more feature complete, please
contact me at <code class="prettyprint">silas@sewell.ch</code>.</p>

<h3>License</h3>

<p>Everything will be BSD.</p>

<h3>Follow-up</h3>

<p>I'll be posting a follow-up with a step-by-step explanation on how to setup a
basic working version of Tyrion in the next week or two.</p>]]></description>
        </item>

        <item>
            <title>txmpp: A BSD Licensed C++ XMPP Library</title>
            <link>http://www.silassewell.com/blog/2010/06/16/txmpp-a-bsd-licensed-cpp-xmpp-library/</link>
            <pubDate>Wed, 16 Jun 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[C++]]></category><category><![CDATA[Fedora]]></category><category><![CDATA[libjingle]]></category><category><![CDATA[txmpp]]></category><category><![CDATA[XMPP]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/06/16/txmpp-a-bsd-licensed-cpp-xmpp-library/</guid>
            <description><![CDATA[<p><a href="http://github.com/tidg/txmpp">txmpp</a> is a permissively licensed (BSD) C++ XMPP library based on
<a href="http://code.google.com/p/libjingle/">libjingle</a>.</p>

<p>The goals for txmpp and why it's a separate project from libjingle are as
follows:</p>

<ul>
<li>All code is under a single, unified namespace</li>
<li>All code is permissively licensed</li>
<li>Good build and install support for POSIX operating systems</li>
<li>Focus on core XMPP components (the <a href="http://xmpp.org/extensions/xep-0166.html">XEP-0166</a> related code has been removed)</li>
</ul>

<p>I've currently got the library building on Fedora 13, CentOS 5 and OS X. In the
near future I'm going to focus on removing the Windows code and reducing the
amount of code not directly tied to core XMPP functionality.</p>

<p>With all that said I want to keep the core as close to libjingle as possible. I
think it's important that txmpp can track and integrate changes from libjingle
in a relatively simple way.</p>

<p>If you're interested in messing around with the library I'd recommend checking
out the sample code in the <a href="http://github.com/tidg/txmpp/tree/master/src/examples/">examples</a> directory.</p>]]></description>
        </item>

        <item>
            <title>node.js HTTPS (SSL) Server Example</title>
            <link>http://www.silassewell.com/blog/2010/06/03/node-js-https-ssl-server-example/</link>
            <pubDate>Thu, 03 Jun 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[HTTPS]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[node.js]]></category><category><![CDATA[SSL]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/06/03/node-js-https-ssl-server-example/</guid>
            <description><![CDATA[<p>A simple HTTPS server using node.js:</p>

<pre><code class="prettyprint">const crypto = require('crypto'),
      fs = require("fs"),
      http = require("http");

var privateKey = fs.readFileSync('privatekey.pem').toString();
var certificate = fs.readFileSync('certificate.pem').toString();

var credentials = crypto.createCredentials({key: privateKey, cert: certificate});

var handler = function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
};

var server = http.createServer();
server.setSecure(credentials);
server.addListener("request", handler);
server.listen(8000);
</code></pre>

<p>You can generate the <code class="prettyprint">privatekey.pem</code> and <code class="prettyprint">certificate.pem</code> files using the
following commands:</p>

<pre><code class="prettyprint">openssl genrsa -out privatekey.pem 1024 
openssl req -new -key privatekey.pem -out certrequest.csr 
openssl x509 -req -in certrequest.csr -signkey privatekey.pem -out certificate.pem
</code></pre>

<p>Update: Thanks to <a href="http://www.geekceo.com/" title="Kord Campbell">Kord Campbell</a> for spotting an issue and sending a fix!</p>]]></description>
        </item>

        <item>
            <title>Auto-reload node.js (OS X)</title>
            <link>http://www.silassewell.com/blog/2010/05/16/auto-reload-node-js-os-x/</link>
            <pubDate>Sun, 16 May 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[JavaScript]]></category><category><![CDATA[node.js]]></category><category><![CDATA[Python]]></category><category><![CDATA[restarter]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/05/16/auto-reload-node-js-os-x/</guid>
            <description><![CDATA[<p><a href="http://github.com/silas/restarter" title="restarter">restarter</a> is a simple Python application which runs a specified
command and restarts the command each time a file event occurs in a specified
directory.</p>

<p>I created restarter because there isn't auto-reload functionality built into
<a href="http://nodejs.org/" title="node.js">node.js</a> (at the time of this post).</p>

<p><strong>Example</strong></p>

<pre><code class="prettyprint">[silas@blackbox keyfu.js]$ restarter node keyfu.js
Express started at http://localhost:3000/ in development mode
</code></pre>

<p><strong>Usage</strong></p>

<pre><code class="prettyprint">Usage: restarter [options] command

Options:
  -h, --help     show this help message and exit
  --path=PATH    directory to watch for file event changes
  --ignore=PATH  specifies events to ignore
</code></pre>]]></description>
        </item>

        <item>
            <title>Jinja2 Markdown Extension</title>
            <link>http://www.silassewell.com/blog/2010/05/10/jinja2-markdown-extension/</link>
            <pubDate>Mon, 10 May 2010 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[Jinja2]]></category><category><![CDATA[Markdown]]></category><category><![CDATA[Python]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2010/05/10/jinja2-markdown-extension/</guid>
            <description><![CDATA[<p>Below is an example of a Markdown extension for <a href="http://jinja.pocoo.org/2/documentation/" title="Jinja2">Jinja2</a>.</p>

<pre><code class="prettyprint">import jinja2
import jinja2.ext
import markdown2

class Markdown2Extension(jinja2.ext.Extension):
    tags = set(['markdown2'])

    def __init__(self, environment):
        super(Markdown2Extension, self).__init__(environment)
        environment.extend(
            markdowner=markdown2.Markdown()
        )   

    def parse(self, parser):
        lineno = parser.stream.next().lineno
        body = parser.parse_statements(
            ['name:endmarkdown2'],
            drop_needle=True
        )
        return jinja2.nodes.CallBlock(
            self.call_method('_markdown_support'),
            [],
            [],
            body
        ).set_lineno(lineno)

    def _markdown_support(self, caller):
        return self.environment.markdowner.convert(caller()).strip()

env = jinja2.Environment(extensions=[Markdown2Extension])

text = """ 
{% markdown2 %}
Hello World
===========

 1. One
 2. {{ two }}
 3. Three
{% endmarkdown2 %}
"""

html = env.from_string(text).render(two='Two')

print html
</code></pre>

<p>Which would result in the following output:</p>

<pre><code class="prettyprint">&lt;h1&gt;Hello World&lt;/h1&gt;

&lt;ol&gt;
&lt;li&gt;One&lt;/li&gt;
&lt;li&gt;Two&lt;/li&gt;
&lt;li&gt;Three&lt;/li&gt;
&lt;/ol&gt;
</code></pre>]]></description>
        </item>

        <item>
            <title>Google App Engine Middleware (gaem)</title>
            <link>http://www.silassewell.com/blog/2009/12/29/google-app-engine-middleware-gaem/</link>
            <pubDate>Tue, 29 Dec 2009 00:00:00 GMT</pubDate>
            <dc:creator>silas</dc:creator>
            <category><![CDATA[Fedora]]></category><category><![CDATA[gaem]]></category><category><![CDATA[Google]]></category><category><![CDATA[Google App Engine]]></category><category><![CDATA[Projects]]></category><category><![CDATA[Python]]></category><category><![CDATA[Reverse Proxy]]></category><category><![CDATA[Software]]></category>
            <guid isPermaLink="true">http://www.silassewell.com/blog/2009/12/29/google-app-engine-middleware-gaem/</guid>
            <description><![CDATA[<p><a href="http://github.com/silas/gaem" title="Google App Engine Middleware">Google App Engine Middleware</a> (gaem) is a collection of utilities for
hosting external sites on Google App Engine.</p>

<p>I created gaem because I wanted to host my blog on an unreliable server and let
Google App Engine serve the content while my server was down or in maintenance
mode.</p>

<p>The basic design is similar to that of <a href="http://docs.djangoproject.com/en/dev/topics/http/middleware/" title="Django's middleware">Django's middleware</a>. A request
travels through a list of components which can either manipulate the request or
provide a response. The response is filtered back through the components and
served to the requester.</p>

<p>A basic implementation looks something like</p>

<pre><code class="prettyprint">import gaem
import gaem.middleware
import gaem.middleware.cache
import gaem.middleware.dos
import gaem.middleware.fetch

URL = 'http://www.example.org'

MIDDLEWARE_CLASSES = (
    gaem.middleware.cache.Memcache(),
    gaem.middleware.cache.Datastore(),
    gaem.middleware.dos.DoS(),
    gaem.middleware.fetch.Fetch(url=URL),
)

application = gaem.Application(MIDDLEWARE_CLASSES)

if __name__ == '__main__':
    application.run()
</code></pre>

<p>When a request first hits this application it is handled by the Memcache
component. This basic caching component checks the Google App Engine Memcache
service to see if the page is in the cache. If so it simply returns the cached
response, otherwise the request proceeds to the Datastore component which does
pretty much the same thing except it uses Google Datastore for persistence. If
both caching components fail the the request goes through a DoS protection
component and is finally retrieved from the backend server by the Fetch
component.</p>

<p>Using a setup like this gaem acts as a rudimentary reverse proxy and while most
of the functionality I've implemented thus far is for this type setup, I plan
on adding features not traditionally found in a reverse proxy.</p>

<h3>Current Features</h3>

<ul>
<li><a href="http://github.com/silas/gaem/blob/a9d187f65229796c1e92b479735f215c4f1e7000/gaem/middleware/cache.py" title="Caching">Caching</a></li>
<li><a href="http://github.com/silas/gaem/blob/a9d187f65229796c1e92b479735f215c4f1e7000/gaem/middleware/fetch.py" title="Backend fetch">Backend fetch</a></li>
<li>Gracefully handle a dead backend</li>
<li><a href="http://github.com/silas/gaem/blob/a9d187f65229796c1e92b479735f215c4f1e7000/gaem/middleware/dos.py" title="DoS protection">DoS protection</a></li>
<li><a href="http://github.com/silas/gaem/blob/a9d187f65229796c1e92b479735f215c4f1e7000/gaem/middleware/api.py" title="API for expiring content">API for expiring content</a></li>
</ul>

<h3>Possible Future Features</h3>

<ul>
<li>Initial and periodic crawler (pre-cache and other hooks)</li>
<li>RESTful API for managing content (put, delete, etc...)</li>
<li>Web interface</li>
<li>XSS protection</li>
<li>Some ESI support</li>
</ul>

<p>But what makes gaem really cool for developers is how easy it is to create
custom components.</p>

<p>A basic component looks like</p>

<pre><code class="prettyprint">from gaem import middleware

class DoesNothing(middleware.Base):

    def process_request(self, request):
        return request

    def process_response(self, response, request):
        return response
</code></pre>

<p>A default gaem component should inherit from <code class="prettyprint">gaem.middleware.Base</code> and
implement <code class="prettyprint">process_request</code> and/or <code class="prettyprint">process_response</code>.</p>

<p>The <code class="prettyprint">process_request</code> function lets you either manipulate the request (ex:
strip the "cookie" header) and pass it along or use the request to create and
return a response (ex: do a fetch to the backend server). The
<code class="prettyprint">process_response</code> function lets you filter the response (ex: translate body
into pig latin) and do side affects (ex: store response in memcache) before the
response is sent to the requester.</p>

<p>The Request/Response objects are borrowed from <a href="http://pythonpaste.org/webob/" title="WebOb">WebOb</a> and can be
manipulated using the interfaces defined in the <a href="http://pythonpaste.org/webob/modules/webob.html" title="WebOb documentation">WebOb documentation</a>.</p>

<p>gaem is currently pretty rough and likely to change over the next couple of
months, but if you're a Python hacker I'd love to hear some feedback
(<a href="http://www.silassewell.com/about/contact/" title="Contact Silas Sewell">contact me</a> or <a href="http://github.com/silas/gaem/issues" title="gaem issues">submit an issue</a>).</p>

<p>P.S. You can see the application I created for this site in the <a href="http://github.com/silas/gaem/tree/master/examples/wordpress/" title="gaem WordPress example">examples directory</a>.</p>]]></description>
        </item>

    </channel>
</rss>
