<?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>Silas Sewell - July 2010</title>
        <atom:link href="http://www.silassewell.com/blog/2010/07/rss2.xml" rel="self" type="application/rss+xml" />
        <link>http://www.silassewell.com/blog/2010/07</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>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>

    </channel>
</rss>
