<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>en.credativ blog: Category Open Source</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/" />
    <link rel="self" type="application/atom+xml" href="http://blog.credativ.com/en/atom.xml" />
    <id>tag:blog.credativ.com,2010-03-05:/en//2</id>
    <updated>2011-06-07T14:33:32Z</updated>
    <subtitle>All about Linux and Open Source</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.34-en</generator>

<entry>
    <title>credativ and OpenERP Partner to Take on Proprietary ERP Giants</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2011/06/-rugby-uk---6.html" />
    <id>tag:blog.credativ.com,2011:/en//2.199</id>

    <published>2011-06-07T14:12:03Z</published>
    <updated>2011-06-07T14:33:32Z</updated>

    <summary> Rugby, UK - 6 June 2011 credativ Ltd, the UK branch of the largest independent provider of Open Source consultancy in Europe, today announced that it is partnering with OpenERP in a move aimed at increasing OpenERP&#8217;s share of...</summary>
    <author>
        <name>Irenie White</name>
        <uri>http://www.credativ.co.uk</uri>
    </author>
    
        <category term="News" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="news" label="News" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="openerp" label="OpenERP" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="opensource" label="Open Source" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="partnership" label="Partnership" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="OpenERP_138.png" src="http://blog.credativ.com/en/OpenERP_138.png" width="190" height="46" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /></p>

<p><strong>Rugby, UK - 6 June 2011</strong></p>

<p><a href="http://www.credativ.co.uk/">credativ Ltd</a>, the UK branch of the largest independent provider of Open Source consultancy in Europe, today announced that it is partnering with OpenERP in a move aimed at increasing OpenERP&#8217;s share of the UK enterprise resource planning market (ERP).</p>

<p>Chris Halls, MD, credativ UK, comments on the partnership: &#8220;OpenERP provides a flexible, robust and cost-effective alternative to proprietary systems such as SAP, JD Edwards EnterpriseOne and Sage, and is especially attractive to SMEs that may have previously found the cost of ERP systems prohibitive.&#8221;</p>

<p>&#8220;credativ has already introduced OpenERP to UK SMEs and enterprises in the manufacturing, ecommerce and logistics industries. credativ&#8217;s customers using OpenERP have already realised business benefits including cost savings, streamlined processes, improved visibility and simplified reporting.&#8221;</p>

<p>OpenERP's comprehensive suite of modular applications caters for all major business processes including: CRM, project management, warehouse management, manufacturing, financial management and human resources.</p>

<p>credativ has been providing open source training and consultancy to public and private sector clients since 1999. The credativ team has extensive experience of working with OpenERP; recent implementation work includes delivering customisations for warehousing, accounting, VAT, reporting and Magento e-commerce integration.</p>

<p>Halls continues: &#8220;Our partnership with OpenERP underlines our commitment to improving the system&#8217;s functionality. We want to highlight open source ERP as an alternative to less flexible proprietary platforms, and believe that this new partnership will bring our experience, size and range of services to organisations who are considering OpenERP.</p>

<p>OpenERP&#8217;s modular design allows organisations to introduce or replace existing ERP systems at their own pace without the burden of ongoing licensing costs. We see our partnership with OpenERP as an opportunity to encourage more organisations to make the move to open source.</p>

<p>credativ's unique support offering is available from operating systems to business applications - at scale. Our international <a href="http://www.credativ.co.uk/services/support">OSSC</a> (Open Source Support Centre) provides support and consultancy not only for OpenERP but for all major open source applications and distributions.&#8221;</p>

<p>Committed to actively participating in the Open Source community, members of credativ&#8217;s 40+ developer team regularly contribute to projects with recent input into OpenERP bug fixes, banking functionality and VAT reporting modules.</p>

<p><strong>About credativ:</strong></p>

<p>Founded in 1999, credativ is an independent consulting and services company which operates from Germany, the U.K., Canada, and the U.S. With a large team of experts in open source software, credativ offers a vast knowledge base that can be tapped into at any time by its clients. The company focuses on the service and support of open source software with a comprehensive range of services, including open source consulting, architectural and technical advice, open source software development, open source training, and personalised support. credativ is &#8220;Your One-Stop Shop for Open Source Support<small>TM</small>&#8221;.</p>]]>
        
    </content>
</entry>

<entry>
    <title>[Tip] Configuring SSH Jumphosts</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2011/05/tip-configuring-ssh-jumphosts.html" />
    <id>tag:blog.credativ.com,2011:/en//2.161</id>

    <published>2011-05-16T14:27:00Z</published>
    <updated>2011-06-27T11:29:52Z</updated>

    <summary> The System Administrator will often come across a situation where an SSH connection to Host B is only possible by making a detour via SHH to Host A: client -&gt; ssh A -&gt; ssh B To shorten this two-step...</summary>
    <author>
        <name>Roland Wolters</name>
        <uri>http://www.credativ.de</uri>
    </author>
    
        <category term="Linux" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Security" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Tip" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="credativ" label="credativ" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="jumphosts" label="Jumphosts" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="linux" label="Linux" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="ssh" label="SSH" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="tip" label="Tip" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="tux.jpg" src="/de/static/tux.jpg" width="86" height="102" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><br />
The System Administrator will often come across a situation where an SSH connection to Host B is only possible by making a detour via SHH to Host A:<br />
client -> ssh A -> ssh B</p>

<p>To shorten this two-step process, an entry can be made in the <tt>~/.ssh/config</tt> of Host A as "Jumphost", to ensure that this step is always followed in future.</p>
<pre class='brush: text'>
Host Bdirekt
Hostname $IP_von_B
User rwo 
ProxyCommand ssh root@A.intern.lan nc %h %p
</pre><p><br />
In the first row an alias is defined - this can be arbitrary, but some relation to B would make sense.  The second row defines the host name of B - for permissions in every network thereafter, an IP is a good idea as a hostname! The option ProxyCommand defines the underlying Jump function - where access via SSH to A and the pipe of data occurs by means of numerical control.</p>

<p>Where SSH keys are properly allocated, there are no more queries.  A simple <tt>ssh Bdirect</tt> leads directly to host B.</p>

<p>All tips in this blog can be found in the <a href="/en/tip/">Tip Category</a>. Should you need further <a href="http://www.credativ.co.uk/services/support/">Support for Linux</a>, you've come to the right place at credativ.</p>]]>
        
    </content>
</entry>

<entry>
    <title>Changing Windows Internet Shortcut (*.url) files into GNOME desktop files</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2011/02/changing-windows-internet-shortcut-url-files-into-gnome-desktop-files.html" />
    <id>tag:blog.credativ.com,2011:/en//2.197</id>

    <published>2011-02-13T02:12:12Z</published>
    <updated>2011-02-13T03:01:14Z</updated>

    <summary> Recursively finding Windows Internet Shortcut (*.url) files and changing them into GNOME desktop files Over the past few days I have finally converted my wife&apos;s computer from WinXP to Linux (Ubuntu 10.10). One of the many fine points of...</summary>
    <author>
        <name>Joe Conway</name>
        <uri>http://www.credativ.us</uri>
    </author>
    
        <category term="Debian" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Linux" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Tip" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="bashlinuxubuntudebianshelldesktop" label="bash linux ubuntu debian shell desktop" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="tux.jpg" src="http://blog.credativ.com/en/static/tux.jpg" width="86" height="102" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><br />
<em>Recursively finding Windows Internet Shortcut (*.url) files and changing them into GNOME desktop files</em></p>

<p>Over the past few days I have finally converted my wife's computer from WinXP to Linux (Ubuntu 10.10). One of the many fine points of the negotiation leading to this was that I needed to preserve her <em>many</em> Internet Shortcut files. Since she has literally thousands of them, and they are sprinkled about in many a nested folder, I needed a script that could find them, and create the equivalent GNOME desktop files. The following is my solution. Perhaps not the most elegant way to achieve these ends, but it worked great for me. However I cannot promise this script will not eat your files, so please test and use at your own risk ;-)</p>

<p>Create the following script (e.g. using vi)</p>
<pre class='brush: text'>
vi /usr/local/bin/fix_url.sh
</pre><p></p>

<p>Put the following in fix_url.sh (press "i", and then type or paste):</p>
<pre class='brush: text'>
#!/bin/bash

(
    IFS=$'\n'
    files=$(find . -name *.url)
    for fl in $files; do
        NEWFILE=${fl}.desktop
        cp &quot;${fl}&quot; &quot;${NEWFILE}&quot;
        sed -i 's/InternetShortcut/Desktop\ Entry/g' &quot;${NEWFILE}&quot;
        sed -i '/^\[DEFAULT\]/d' &quot;${NEWFILE}&quot;
        sed -i '/^BASEURL/d' &quot;${NEWFILE}&quot;
        sed -i '/^IconFile/d' &quot;${NEWFILE}&quot;
        sed -i '/^IconIndex/d' &quot;${NEWFILE}&quot;
        sed -i 's/\r$//' &quot;${NEWFILE}&quot;
        echo &quot;Type=Link&quot; &gt;&gt; &quot;${NEWFILE}&quot;
    done
)
</pre><p><br />
Save the file by typing ":x" if you used vi.</p>

<p>Make it executable:</p>
<pre class='brush: text'>
chmod +x /usr/local/bin/fix_url.sh
</pre><p></p>

<p>Test/run the new script. Do this first on an isolated test location, e.g. copy some Windows Internet Shortcut files to /tmp/windows_urls:</p>
<pre class='brush: text'>
cd /tmp
/usr/local/bin/fix_url.sh
</pre><p></p>

<p>Check out the resulting *.desktop files. Verify they look correct, and that they actually work when clicked from Nautilus, etc.</p>

<p>If completely satisfied, change to the root of the real directory tree and re-run the script.</p>

<p>When you are all finished, the original *.url files are still hanging around. If you want to get rid of them (again <em>test first</em>):</p>
<pre class='brush: text'>
cd /tmp
find . -name *.url -delete
</pre><p></p>

<p>Hope this helps someone else!<br />
</p>]]>
        
    </content>
</entry>

<entry>
    <title>credativ and Black Duck announce International Partnership</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/12/credativ-black-duck-partnership.html" />
    <id>tag:blog.credativ.com,2010:/en//2.195</id>

    <published>2010-12-06T15:13:54Z</published>
    <updated>2010-12-07T10:11:59Z</updated>

    <summary> Rugby, 6 December 2010 - credativ Ltd and Black Duck Software Inc. have announced an international partnership to help further the deployment and integration of Open Source Software. The OSSC (Open Source Support Centre) run by credativ in the...</summary>
    <author>
        <name>Irenie White</name>
        <uri>http://www.credativ.co.uk</uri>
    </author>
    
        <category term="News" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Support" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="blackduck" label="black duck" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="news" label="news" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="opensourcesupport" label="open source support" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="partnership" label="partnership" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="black duck image.jpeg" src="http://blog.credativ.com/en/2010/12/06/black%20duck%20image.jpeg" width="70" height="70" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /></p>

<p><em><strong>Rugby, 6 December 2010</strong> - credativ Ltd and Black Duck Software Inc. have announced an international partnership to help further the deployment and integration of Open Source Software.</em></p>

<p>The <a href="http://www.credativ.co.uk/services/support/">OSSC</a> (Open Source Support Centre) run by credativ in the UK, US, Germany and Canada will now also be providing support for customers of Black Duck Software Inc. </p><p><a href="http://www.blackducksoftware.com/news/releases/2010-11-30/">Black Duck Software</a> is a worldwide provider of &#8220;managed software component reuse&#8221; solutions; they support businesses and organisations who use Open Source and third party source code in adhering to relevant licensing obligations, thereby reducing the associated business risks.</p><p>Through this partnership with credativ, Black Duck can now also offer comprehensive technical support for the many free software projects which are developed through extensive developer communities rather than through an organisation. This service guarantees Black Duck customers additional security for complex <a href="http://credativ.co.uk/services/">Open Source services</a> and provides an alternative which is comparable to the manufacturer's support available with proprietary software.</p><p>Mr. Chris Halls, Managing Director of credativ Ltd in the UK, explains: </p><p>&#8220;We are delighted about the partnership with Black Duck. We hope that combining our competencies will enable us to cover all the requirements for safe operation of Open Source software. Our partnership is a good basis for further international expansion - our Open Source Support Centres will be enhancing Black Duck's service offering, not only for the US but also the European market.&#8221;</p>

<p>If you would like to know more about our Open Source involvement simply leave us a comment here... alternatively please <a href="http://www.credativ.co.uk/contact/">contact us</a> directly.</p>

<p style="margin-bottom: 0cm; widows: 0; orphans: 0;" class="western"><strong>About credativ</strong></p><p style="margin-bottom: 0cm; widows: 0; orphans: 0;" class="western"><span>Founded
in 1999, credativ is an independent consulting and services company
which operates from Germany, the U.K., Canada, and the U.S. With a
large team of experts in open source software, credativ offers a vast
knowledge base that can be tapped into by its clients. The company
focuses on the service and support of open source software with a
comprehensive range of services, including open source consulting,
architectural and technical advice, open source software development,
open source training, and personalized support. credativ is &#8220;Your
One-Stop Shop for Open Source Support&#8221; </span><sup><span>TM</span></sup><span>.</span></p><p>The Open Source Support Centre (OSSC) offers support for the following:</p><p><em>Debian,
Kubuntu, Ubuntu, Xandros, SUSE, Red Hat, Fedora, CentOS, Linspire,
Mandriva, Slackware, Open BSD, Gnome, KDE, MySQL, PostgreSQL, PostGIS,
Slony, Zarafa, eGroupware, Kolab Groupware, Scalix, SugarCRM, vtiger,
CITADEL, Mozilla-Firefox, Mozilla-Suite, OpenOffice, Thunderbird, Wine,
Apache, Asterisk, OpenSER, FreePBX, OpenPBX, CallWeaver, SpamAssassin,
ClamAV, OpenLDAP, OTRS, RT, Samba, Cyrus, Dovecot, Exim, Postfix,
sendmail, Amanda, Bacula, DRBD, Heartbeat, Keepalived, Nagios, Open
Security Filter, Ferm, FAI, Squid, XEN, VirtualBox.</em></p><p>For further information please contact: </p><p>
credativ Ltd,<br />
36 Regent Street,<br />
Rugby,<br />
Warwickshire,<br />
CV21 2PS</p><h4>Press contact</h4><p>
Simon Bowring
</p><p>
Tel: +44 (0) 1788 298150<br />
Fax: +44 (0) 1788 298159<br />
Email: <a href="mailto:simon.bowring@credativ.co.uk">simon.bowring@credativ.co.uk</a></p><p class="western" style="margin-bottom: 0cm; font-style: normal; font-weight: normal; text-decoration: none;" lang="en-GB"><span><strong>About Black Duck Software Inc</strong></span></p><p style="margin-bottom: 0cm; widows: 0; orphans: 0;" class="western">Black
Duck Software is the leading provider of products and services for
automating the management, governance and secure use of open source
software, at enterprise scale, in a multi-source development process.
Black Duck™ enables companies to shorten time-to-solution and
reduce development costs while mitigating the management, compliance
and security challenges associated with open source software.&#160; Black
Duck Software powers Koders.com, the industry&#8217;s leading code search
engine for open source, and is among the 500 largest software
companies in the world, according to Softwaremag.com. The company is
headquartered near Boston and has offices in San Mateo, California,
London, Paris, Frankfurt, Hong Kong, Tokyo and Beijing.</p><p style="margin-bottom: 0cm; widows: 0; orphans: 0;" class="western">For
more information, visit <a href="http://www.blackducksoftware.com/">www.blackducksoftware.com</a>.&#160;</p><p style="margin-bottom: 0cm; widows: 0; orphans: 0;" class="western"><em>Black
Duck, Know Your Code and the Black Duck logo are registered
trademarks of Black Duck Software, Inc. in the United States and
other jurisdictions. Koders is a trademark of Black Duck Software,
Inc. All other trademarks are the property of their respective
holders.</em></p><h4>Press contacts</h4><p class="western" style="margin-bottom: 0cm; font-style: normal; text-decoration: none;" lang="en-GB"><strong><strong>Peter
Vescuso</strong></strong><br />Black Duck
Software<br /><a href="http://press@blackducksoftware.com/">press@blackducksoftware.com
</a><br />+1 781-891-5100</p><p class="western" style="margin-bottom: 0cm; font-style: normal; text-decoration: none;" lang="en-GB"><strong><strong>Ann
Dalrymple</strong></strong><br />TopazPartners</p>]]>
        
    </content>
</entry>

<entry>
    <title>Open Source lives - PostgreSQL developers at credativ</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/09/open-source-lives---postgresql-developers-at-credativ.html" />
    <id>tag:blog.credativ.com,2010:/en//2.175</id>

    <published>2010-09-20T14:00:34Z</published>
    <updated>2010-09-20T13:56:42Z</updated>

    <summary> Earlier this year, blogger and PostgreSQL Committer Andrew Dunstan drew up a list of individual Committers to the PostgreSQL Project. We are proud to say that this list featured some of our employees. In May, PostgreSQL&apos;s Andrew Dunstan published...</summary>
    <author>
        <name>Irenie White</name>
        <uri>http://www.credativ.co.uk</uri>
    </author>
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="PostgreSQL" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="postgreslogo.png" src="/de/static/postgreslogo.png" width="97" height="100" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><br />
<em>Earlier this year, blogger and PostgreSQL Committer Andrew Dunstan drew up a list of individual Committers to the PostgreSQL Project. We are proud to say that this list featured some of our employees.</em><br />
<br/><br />
In May, PostgreSQL's Andrew Dunstan published some data about the productivity of PostgreSQL Committers at <a href="http://people.planetpostgresql.org/andrew/index.php?/archives/79-30,000-commits-and-still-going-strong.html/">30,000 commits and still going strong</a>, detailing the number of commits made by developers with commit rights. Incidentally, becoming a Committer is no mean feat; although there is no set procedure for acquiring the right to commit, it will generally follow a candidate having sent numerous good patches over a long period of time. Existing Committers, or the core team will then propose and approve assigning Committer's rights to the candidate. </p>

<p>credativ can claim involvement with many other Open Source Projects in addition to PostgreSQL. Community involvement is taken seriously at credativ, as is evident from Andrew Dunstan's statistics. A few of the Committers mentioned work at various international credativ offices; Michael Meskes, Joe Conway and Dave Cramer. What is not clear from Dunstan's list is the number of credativ employees who contribute large amounts of code but are not actually Committers; take Bernd Helmle, for example, who readers of this blog will be familiar with from his <a href="http://blog.credativ.com/en/postgresql/">PostgreSQL articles</a> not only as author but also as a developer, yet he does not feature in Andrew's statistics.</p>

<p>Nevertheless credativ's presence on this list is indicative of our achievements as well as our employees' connections with Open Source; if you would like to know more about our Open Source involvement simply leave us a comment here... and if you are interested in <a href="http://www.credativ.co.uk/services/support/">Open Source Support</a>, please <a href="http://www.credativ.co.uk/contact/">contact us</a>.<br />
</p>]]>
        
    </content>
</entry>

<entry>
    <title>CIOZone Interview</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/08/ciozone-interview.html" />
    <id>tag:blog.credativ.com,2010:/en//2.186</id>

    <published>2010-08-11T14:55:23Z</published>
    <updated>2010-08-11T14:55:29Z</updated>

    <summary>CIOZone, a social network for CIOs, recently interviewed our Founder and CEO Dr. Michael Meskes. CIOZone is a central place where CIOs can network. In this video, Roger Green takes the time to drop in to our office in Moenchengladbach,...</summary>
    <author>
        <name>Lukas Gärtner</name>
        <uri>http://blog.credativ.de</uri>
    </author>
    
        <category term="News" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><a href="http://blog.credativ.com/de/assets_c/2010/08/mme-ciozone-79.html" onclick="window.open('http://blog.credativ.com/de/assets_c/2010/08/mme-ciozone-79.html','popup','width=443,height=324,scrollbars=no,resizable=no,toolbar=no,directories=no,location=no,menubar=no,status=no,left=0,top=0'); return false"><img src="http://blog.credativ.com/de/assets_c/2010/08/mme-ciozone-thumb-100x73-79.png" width="100" height="73" alt="mme-ciozone.png" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /></a><em>CIOZone, a social network for CIOs, recently interviewed our Founder and CEO Dr. Michael Meskes.</em><br/><br />
CIOZone is a central place where CIOs can network. In this video, Roger Green takes the time to drop in to our office in Moenchengladbach, Germany to interview Michael Meskes, the founder of <a href="http://www.credativ.com">credativ</a> about the history of the company, how Open Source has developed and how the business is different today from what it was 10 years ago.</p>

<p>This discussion is followed by analysis of current development and future challenges; the difference between Open Source vendors and proprietary global players; virtualisation and cloud computing in relation to Open Source and what to keep in mind when migrating to Open Source software.</p>

<p>Read on or watch the video at <a href="http://www.ciozone.com/index.php/Open-Source-Video/Interview-with-Dr.-Michael-Meskes-Founder/CEO-Credativ-GMBH-Germany.html">ciozone.com</a>.</p>

<p>If you're looking for support, services and <a href="http://www.credativ.co.uk/services/training">training</a> for Open Source software, you've come to the right place at credativ!</p>]]>
        
    </content>
</entry>

<entry>
    <title>PostgreSQL topic of the Day - PL/R performance improvements</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/07/postgresql-topic-of-the-day---plr-performance-improvements.html" />
    <id>tag:blog.credativ.com,2010:/en//2.184</id>

    <published>2010-07-24T18:31:12Z</published>
    <updated>2010-07-24T20:30:16Z</updated>

    <summary>When you pass large amounts of data to and from PL/R, quite a lot of time is needed for converting. A change is being tested which treats arrays of 4 byte integers and 8 byte floating point values as a...</summary>
    <author>
        <name>Joe Conway</name>
        <uri>http://www.credativ.us</uri>
    </author>
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="PostgreSQL" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="analytics" label="analytics" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plr" label="PL/R" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="postgresql" label="PostgreSQL" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="r" label="R" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="postgreslogo.png" src="/de/static/postgreslogo.png" width="97" height="100" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><img alt="Rlogo.jpg" src="http://blog.credativ.com/en/Rlogo.jpg" width="100" height="76" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><em>When you pass large amounts of data to and from PL/R, quite a lot of time is needed for converting. A change is being tested which treats arrays of 4 byte integers and 8 byte floating point values as a special case, resulting in a dramatic performance improvement.</em></p>

<p>In a recent post, I discussed PL/R performance related to seismic timeseries data stored as an array of floats that are all recorded during some seismic event at a constant sampling rate. The problem was that when dealing with, say, 14000 arrays of floats, each having on the order of 16000 elements, passing the data to and from PL/R proved slower than hoped.</p>

<p>My ultimate solution was to show how a significant performance improvement could be achieved by importing the arrays into Postgres tables directly as raw R objects, and then operating on those objects later using PL/R. The problem with this approach is that in some, if not most, cases, you may want to access that same data from other procedural languages or hand off the arrays to some client other than R. In this case the raw R object does not meet your needs.</p>

<p>So I thought about it a bit and researched the source code on the Postgres and R sides of PL/R, and concluded that for certain special cases it was possible to dramatically improve speed by skipping the one-at-a-time element conversion as arrays are processed going between PostgreSQL and R. Specifically, the in-memory storage of the array data is binary compatible in the following circumstances:<br />
<ol><li>pgsql -> R</li><ul><li>Argument is integer or double precision array</li><li>Element data type is pass-by-value for given Postgres version and architecture</li><li>No NULL elements</li><li>Array is one dimensional</li></ul><li>R -> pgsql</li><ul><li>Integer vector returned with integer array return type</li><li>Real vector returned with double precision array return type</li><li>No NA elements</li><li>One dimensional vector</li></ul></ol></p>

<p>Pass-by-value is most likely true for double precision (float8) if PostgreSQL is at least version 8.4 and was built with a 64 bit system architecture. If these conditions are met, PL/R now simply copies en masse the in-memory array data from the PostgreSQL array data structure to the R vector data structure. This avoids all the overhead associated with iterating over the array element by element. Although I am not a fan of special case code such as this, the use case is important (if you are crunching numbers, they are likely stored as double precision elements), and the performance benefit is huge. Here is the timing difference with the patched PL/R versus the unpatched PL/R:<br />
</p>
<pre class='brush: sql'>
DROP TABLE IF EXISTS test_ts;
CREATE TABLE test_ts
(
  dataid bigint NOT NULL,
  data double precision[],
  CONSTRAINT pk_data PRIMARY KEY (dataid)
);

CREATE OR REPLACE FUNCTION load_test(int) RETURNS text AS $$
 DECLARE
  i    int;
 BEGIN
  FOR i IN 1..$1 LOOP
   --16789 double precision elements in the data array
   INSERT INTO test_ts (dataid, data) VALUES (i, '{-0.0205086770285039,...}');
  END LOOP;
  RETURN 'OK';
 END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION
filt_r_nothing(ts double precision[])
RETURNS double precision[] AS $$
  return(ts);
$$ LANGUAGE 'plr' IMMUTABLE;

CREATE OR REPLACE FUNCTION
filt_r_avg(ts double precision[])
RETURNS double precision AS $$
  return(mean(ts));
$$ LANGUAGE 'plr' IMMUTABLE;

-- INSERT 14000 rows of 16789 element arrays
SELECT load_test(14000);

-- unpatched code
UPDATE test_ts SET data = filt_r_nothing(data);
UPDATE 14000
Time: 1224087.064 ms

-- patched code
UPDATE test_ts SET data = filt_r_nothing(data);
UPDATE 14000
Time: 225591.429 ms

-- unpatched code
contrib_regression=# select filt_r_avg(data) from test_ts;
    filt_r_avg     
-------------------
 0.656530643017027
 0.656530643017027
[...]
(14000 rows)
Time: 441573.619 ms

-- patched code
contrib_regression=# select filt_r_avg(data) from test_ts;
    filt_r_avg     
-------------------
 0.656530643017027
 0.656530643017027
[...]
(14000 rows)
Time: 6541.039 ms

-- unpatched code
select array_upper(filt_r_nothing(data),1) from test_ts;
 array_upper 
-------------
       16879
       16879
[...]
(14000 rows)
Time: 1108651.349 ms

-- patched code
select array_upper(filt_r_nothing(data),1) from test_ts;
 array_upper 
-------------
       16879
       16879
[...]
(14000 rows)
Time: 23101.602 ms
</pre><p><br />
So to summarize:<table><tr color="gray"><td>Test</td><td>Case</td><td>Time (ms)</td><td>Improvement</td></tr><tr><td>UPDATE NOOP</td><td>Unpatched</td><td>1224087.064</td><td>--</td></tr><tr><td>UPDATE NOOP</td><td>Patched</td><td>225591.429</td><td>82%</td></tr><tr><td>SELECT AVG</td><td>Unpatched</td><td>441573.619</td><td>--</td></tr><tr><td>SELECT AVG</td><td>Patched</td><td>6541.039</td><td>98%</td></tr><tr><td>SELECT NOOP</td><td>Unpatched</td><td>1108651.349</td><td>--</td></tr><tr><td>SELECT NOOP</td><td>Patched</td><td>23101.602</td><td>98%</td></tr></table></p>

<p>Pretty substantial improvement in these particular, but I think common, use cases. The UPDATE test sees less overall benefit because the time to write out the changes would be significant and the same regardless of array handling in PL/R. The difference between SELECT NOOP and SELECT AVG is driven by the fact that the latter returns a scalar result, while the former returns the entire array. The reason SELECT NOOP does array_upper() on the returned array, is that otherwise all that array data (something like 4 GB) gets materialized in memory by psql, which of course greatly slows things further and is not what we are trying to test.</p>

<p>Please give the changes a try and provide feedback before I release another PL/R version. You can grab the new code from <a href="http://github.com/jconway/plr">github</a> and sign up for the <a href="http://pgfoundry.org/mail/?group_id=1000247">PL/R mailing list</a> to post your results or report any questions/problems. And of course visit the <a href="http://www.joeconway.com/plr/">PL/R homepage</a> and <a href="http://www.joeconway.com/web/guest/pl/r">PL/R wiki</a> for more general information about PL/R -- particularly to watch for these changes in the next official release. Finally, don't hesitate to <a href="http://www.credativ.us/contact/">contact me</a> directly if the other choices don't suit you for some reason.</p>]]>
        
    </content>
</entry>

<entry>
    <title>PostgreSQL topic of the Day - advanced analytics</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/07/postgresql-topic-of-the-day---advanced-analytics.html" />
    <id>tag:blog.credativ.com,2010:/en//2.183</id>

    <published>2010-07-12T02:58:22Z</published>
    <updated>2010-12-07T12:43:00Z</updated>

    <summary>When you pass large amounts of data to and from PL/R, quite a lot of time is needed for converting. It&apos;s better to directly store the data as R objects. I had been planning to continue with timeseries aggregation, but...</summary>
    <author>
        <name>Joe Conway</name>
        <uri>http://www.credativ.us</uri>
    </author>
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="PostgreSQL" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="analytics" label="analytics" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="plr" label="PL/R" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="postgresql" label="PostgreSQL" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="r" label="R" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="postgreslogo.png" src="/de/static/postgreslogo.png" width="97" height="100" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><img alt="Rlogo.jpg" src="http://blog.credativ.com/en/Rlogo.jpg" width="100" height="76" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><em>When you pass large amounts of data to and from PL/R, quite a lot of time is needed for converting. It's better to directly store the data as R objects.</em></p>

<p>I had been planning to continue with timeseries aggregation, but decided to take a side-road based on a recent question on the <a href="http://www.joeconway.com/plr">PL/R</a> mailing list.</p>

<p>The question was related to seismic data, which is in fact timeseries data. However, I guess the data is normally stored as an array of floats that are all recorded during some seismic event at a constant sampling rate. The arrays are available from online sources in an individual file for each event being analyzed. The problem was that when dealing with, say, 14000 arrays of floats, each having on the order of 16000 elements, passing the data to and from PL/R proved slower than hoped.</p>

<p>So we start with loading of sample data for a performance test:</p>
<pre class='brush: sql'>DROP TABLE IF EXISTS test_ts;
CREATE TABLE test_ts
(
  dataid bigint NOT NULL,
  data double precision[],
  CONSTRAINT pk_data PRIMARY KEY (dataid)
);

CREATE OR REPLACE FUNCTION filt_r_nothing(ts double precision[])
RETURNS double precision[] AS $$
 return(ts);
$$ LANGUAGE 'plr' IMMUTABLE;

CREATE OR REPLACE FUNCTION load_test(int) RETURNS text AS $$
  DECLARE
   i    int;
  BEGIN
    FOR i IN 1..$1 LOOP
      INSERT INTO test_ts(dataid,data) VALUES (i,'{-0.0205086770285039, ...'})
    END LOOP;
    RETURN 'OK';
  END;
$$ LANGUAGE plpgsql;

SELECT load_test(14000);
 load_test 
-----------
 OK
(1 row)

Time: 123861.362 ms
</pre><p></p>

<p>The array in the VALUES clause of that function actually contains 16879 float8 elements. You can see that it takes over two minutes on my development machine to load the table with 14000 rows of this array. Note that on my development machine I have done no tuning of PostgreSQL configs, and I built with --enable-debug, --enable-cassert, and CFLAGS='-O0 -g3'.</p>

<p>Next, we update the data column with filt_r_nothing() which does nothing other than returning the same array it was passed.<br />
</p>
<pre class='brush: sql'>UPDATE test_ts SET data = filt_r_nothing(data);
UPDATE 14000
Time: 1224087.064 ms
</pre><p></p>

<p>Not pretty. Over 20 minutes. I did some profiling of PL/R and concluded most of the time was being spent converting 16879 PostgreSQL array elements from float8 datums to R vector elements one at a time while processing the function argument, and then repeating the process in reverse while creating the returned result. Perhaps there are optimizations that can be made to that process, but since PostgreSQL and R each have their own binary representation of this data, there is no avoiding the conversion overhead.</p>

<p>However, what is the point of the proposed performance test? The comparison was being made to another procedural language, which apparently does not convert the array elements if they are not used. A real function is presumably going to do some calculation over the array elements, requiring that they be individually accessed.</p>

<p>I decided to see how PL/pgSQL performs if forced to modify and return the passed array. The difference between this test and the PL/R one will give some insight on the time spent converting elements from PostgreSQL to R native form.<br />
</p>
<pre class='brush: sql'>CREATE OR REPLACE FUNCTION
filt_plpgsql_nothing(ts double precision[])
RETURNS double precision[] AS $$
 BEGIN
  RETURN ts || 3.14159::float8;
 END
$$ LANGUAGE 'plpgsql' IMMUTABLE;

UPDATE test_ts SET data = filt_plpgsql_nothing(data);
UPDATE 14000
Time: 239054.580 ms
</pre><p></p>

<p>About 6 minutes. Much better. But let's see what happens if we do some more meaningful, if simple, calculations on the array elements.<br />
</p>
<pre class='brush: sql'>CREATE OR REPLACE FUNCTION
filt_plpgsql_avg(ts double precision[])
RETURNS double precision AS $$
 DECLARE
  i int;
  numts int = array_upper(ts,1);
  ts_sum float8 = 0.0;
 BEGIN
  FOR i IN 1..numts LOOP
    ts_sum := ts_sum + ts[i];
  END LOOP;
  RETURN (ts_sum/numts::float8);
 END
$$ LANGUAGE 'plpgsql' IMMUTABLE;

select filt_plpgsql_avg(data) from  test_ts;
--killed after &gt; 1 hour

CREATE OR REPLACE FUNCTION filt_r_avg(ts double precision[])
RETURNS double precision AS $$
 return(mean(ts));
$$ LANGUAGE 'plr' IMMUTABLE;

contrib_regression=# select filt_r_avg(data) from test_ts;
    filt_r_avg     
-------------------
 0.656530643017027
 0.656530643017027
[...]
(14000 rows)
Time: 441573.619 ms
</pre><p></p>

<p>Although the PL/R function still took over 7 minutes to process 14000 rows with 16879 elements, PL/pgSQL took long enough that I killed it out of impatience.</p>

<p>It occurred to me that a feature I added to PL/R within the past year or so might come in handy about now. Namely, it is possible to directly store R objects in PostgreSQL tables. This means that when the datum is passed to a PL/R function, it is all ready to go -- no conversion needed. Let's take a look at that scenario.<br />
</p>
<pre class='brush: sql'>DROP TABLE IF EXISTS test_ts_obj;
CREATE TABLE test_ts_obj
(
  dataid serial PRIMARY KEY,
  data bytea
);

CREATE OR REPLACE FUNCTION make_r_object(fname text)
RETURNS bytea AS $$
 myvar&lt;-scan(fname,sep=&quot;,&quot;)
 return(myvar);
$$ LANGUAGE 'plr' IMMUTABLE;

INSERT INTO test_ts_obj (data) SELECT make_r_object('array-data.csv') from generate_series(1,14000);
INSERT 0 14000
Time: 44182.598 ms

CREATE OR REPLACE FUNCTION filt_r_avg(ts bytea)
RETURNS double precision AS $$
 return(mean(ts));
$$ LANGUAGE 'plr' IMMUTABLE;

select filt_r_avg(data) from  test_ts_obj;
    filt_r_avg     
-------------------
 0.656530643017027
 0.656530643017027
 [...]
 0.656530643017027
(14000 rows)

Time: 12828.331 ms
</pre><p></p>

<p>This results in 44 seconds to load the same 14000 rows of array data as before, but<br />
directly as R objects. Compare that to the 2 minutes to load as PostgreSQL arrays as seen at the beginning of this article. And now it only takes 13 seconds to operate on the 14000 R objects compared to 442 seconds. That's a nice improvement!</p>

<p>But PL/R gives you access to the full power of the R environment for statistical computing and graphics. Just for fun, here is a PL/R function that calculates the "Power Spectrum" of the seismic data, and returns the result as a JPEG of the plot.<br />
</p>
<pre class='brush: sql'>CREATE OR REPLACE FUNCTION
filt_r_ps(ts bytea)
RETURNS bytea AS $$
  library(quantmod)
  library(cairoDevice)
  library(RGtk2)

  fourier&lt;-fft(ts)
  magnitude&lt;-Mod(fourier)
  y2 &lt;- magnitude[1:(length(magnitude)/10)]
  x2 &lt;- 1:length(y2)/length(magnitude)
  mydf &lt;- data.frame(x2,y2)

  pixmap &lt;- gdkPixmapNew(w=500, h=500, depth=24)
  asCairoDevice(pixmap)

  plot(mydf,type=&quot;l&quot;)
  plot_pixbuf &lt;- gdkPixbufGetFromDrawable(NULL, pixmap,
                                                        pixmap$getColormap(),
                                                        0, 0, 0, 0, 500, 500)
  buffer &lt;- gdkPixbufSaveToBufferv(plot_pixbuf,
                                                       &quot;jpeg&quot;,
                                                        character(0),
                                                        character(0))$buffer
  return(buffer)
$$ LANGUAGE 'plr' IMMUTABLE;
</pre><p></p>

<p>This is now not about performance so much as it is about analytical power. About half of the lines in this function are setting up to capture the output graph. The "meat" of the function can be contained in these few lines:<br />
</p>
<pre class='brush: sql'>fourier&lt;-fft(ts)
magnitude&lt;-Mod(fourier)
plot(x=1:length(y2)/length(magnitude),
       y=magnitude[1:(length(magnitude)/10)],
       type=&quot;l&quot;)
</pre><p></p>

<p>Compliment that PL/R function with a bit of PHP code...<br />
</p>
<pre class='brush: sql'>&lt;?php
function hex2bin($data)
{
	$data = ltrim($data, &quot;\x&quot;);
	$len = strlen($data);
	return pack(&quot;H&quot; . $len, $data);
} 

$dbconn = pg_connect(&quot;dbname=contrib_regression&quot;);
$rs = pg_query( $dbconn, &quot;select plr_get_raw(filt_r_ps(data))
                                    from test_ts_obj where dataid = 42&quot;);
$hexpic = pg_fetch_array($rs);
$cleandata = hex2bin($hexpic[0]);

header(&quot;Content-Type: image/jpeg&quot;);
header(&quot;Last-Modified: &quot; .
date(&quot;r&quot;, filectime($_SERVER['SCRIPT_FILENAME'])));
header(&quot;Content-Length: &quot; . strlen($cleandata));
echo $cleandata;
?&gt;
</pre><p></p>

<p>...and the output looks like:<img alt="plr-blog.jpg" src="/en/jco/plr-blog.jpg" width="500" height="500" class="mt-image-center" style="text-align: center; display: block; margin: 0 auto 20px;" /></p>

<p>Fairly sophisticated output for relatively little effort! For more information or assistance with respect to PostgreSQL, PL/R, and/or advanced analytics, <a href="http://www.credativ.us/contact/">don't hesitate to contact us</a>.</p>]]>
        
    </content>
</entry>

<entry>
    <title>PostgreSQL topic of the Day - aggregating timeseries data</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/07/tip-postgresql-tip-of-the-day---aggregating-timeseries-data.html" />
    <id>tag:blog.credativ.com,2010:/en//2.182</id>

    <published>2010-07-09T00:21:04Z</published>
    <updated>2010-12-07T12:44:45Z</updated>

    <summary>Frequently when dealing with parametric data, you need to &quot;roll up&quot; the data in summary fashion as it ages in order to reduce the volume kept on hand, or maybe because the summary statistics are what really interests you. There...</summary>
    <author>
        <name>Joe Conway</name>
        <uri>http://www.credativ.us</uri>
    </author>
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="PostgreSQL" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="postgresql" label="PostgreSQL" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="postgreslogo.png" src="/de/static/postgreslogo.png" width="97" height="100" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><em>Frequently when dealing with parametric data, you need to "roll up" the data in summary fashion as it ages in order to reduce the volume kept on hand, or maybe because the summary statistics are what really interests you. There are several ways to do that, and this post highlights four different approaches.</em></p>

<p>I was reminded of this kind of "roll ups" today by a question on the pgsql-novice list. This is actually quite a large topic, so I this tip will likely just scratch the surface. The question was related to storing min, max, and avg summaries on an hourly, daily, and weekly basis. The basic idea, for example, is that you can keep raw data for maybe a week, hourly summaries for 6 months, daily summaries for 3 years, and weekly summaries forever. As I mentioned in my reply, I have done this kind of thing over the years using at least 4 approaches:</p>

<ol>
	<li>Aggregate on demand</li>
	<li>Batch aggregate on a periodic basis -- e.g. run your aggregate query with a cron job which truncates and rebuilds a table (i.e. a  "materialized view")</li>
	<li>Write a C based trigger that does "continuous aggregation" to a materialized table</li>
	<li>Write a C based bulk loader that aggregates as it bulk loads the raw  data into a materialized table</li>
</ol>

<p>The first approach is simply to run an aggregate query whenever you need the summarized data. Obviously this does not really satisfy the stated desire to discard aged raw data, but I mention it for completeness. In some cases you have sufficient storage given your data volume, and performance of the aggregate is "good enough".</p>

<p>The second is the rough equivalent of a materialized view. In other words, run a batch job via cron or something similar that <tt>TRUNCATE</tt>s and then repopulates a table used for storage of the aggregate result. Particularly for daily or weekly summary data, when the consumers of the data are 9-5 folk, this approach works pretty well. This also fits in nicely with common partitioning schemes.</p>

<p>The third is one where you want summary statistics to be updated live. In this case you actually want the summary data for the current hour/day/week to all be constantly updated as new raw data comes in. Otherwise you are stuck always looking at last hour's, or yesterday's, or last weeks, data. The way to do this is through a trigger. A while back I implemented a continuous aggregation trigger in C that used prepared queries to update my aggregate table for every <tt>INSERT</tt>/<tt>UPDATE</tt>/<tt>DELETE</tt> occurring on the target table. However even with the trigger written in C and using prepared queries, the performance impact of the trigger firing for every DML event was significant.</p>

<p>Finally, the forth method can be used when your reporting needs are such that the raw data can be collected for some period before storing in your database. Let's say the summary reports are never run against the current hour. What you can do is build up a file in suitable format for bulk loading via <tt>COPY</tt>. Then process the data as it is bulk loaded to calculate and insert the summary at the same time. Again, I had done that in the past using a C program that read in the stored files, generated the summary data while building a string buffer, and finally using libpq's <tt>PQputCopyData()</tt> to populate the tables.</p>

<p>More than likely some combination of the above is what you really want. Perhaps use method 2 to maintain your weekly and daily aggregate materialized views, and use method 4 to update your hourly aggregate data.</p>

<p>This post was a lot of discussion and no code -- perhaps tomorrow I will continue with some more concrete examples.</p>]]>
        
    </content>
</entry>

<entry>
    <title>[Tip] PostgreSQL Tip of the Day - mass modification of sequences</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/07/postgresql-tip-of-the-day---mass-modification-of-sequences.html" />
    <id>tag:blog.credativ.com,2010:/en//2.180</id>

    <published>2010-07-07T21:34:07Z</published>
    <updated>2010-12-07T12:45:11Z</updated>

    <summary>Someone posted a dilemma to the pgsql-sql list today that involved many if not all of his sequences getting out of sync with their respective &quot;serial&quot; columns. In other words, something like &quot;SELECT max(id) FROM sometable&quot; yields 42, but the...</summary>
    <author>
        <name>Joe Conway</name>
        <uri>http://www.credativ.us</uri>
    </author>
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="PostgreSQL" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Tip" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="plpgsql" label="plpgsql" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="postgresql" label="PostgreSQL" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="sequences" label="sequences" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="postgreslogo.png" src="/de/static/postgreslogo.png" width="97" height="100" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" />Someone posted a dilemma to the pgsql-sql list today that involved many if not all of his sequences getting out of sync with their respective "serial" columns. In other words, something like "SELECT max(id) FROM sometable" yields 42, but the sequence nextval for sometable.id is currently set to 36. This is obviously bad (for reasons left as an exercise for the reader). So besides trying to figure out how the database ended up in this state, he needed a script to reset all of his sequences to the correct next value.</p>

<p>I had run into a similar need not too long ago. Namely, when setting up multi-master replication with Bucardo you need your sequences to draw different values on either master so as not to conflict. One solution is to set up all your sequences to jump by 2, and use even numbers on one master and odd numbers on the other. Again, a script makes this easier to deal with, and I had developed one for this situation. So I modified it for the problem mentioned above.</p>

<p>Both versions follow:<br />
</p>
<pre class='brush: sql'>-- create &quot;odd&quot; and &quot;even&quot; sequences in multi-master scenario
CREATE OR REPLACE FUNCTION adjust_seqs(namespace text, starteven bool)
  RETURNS text AS $$
DECLARE
  rec         record;
  startval   bigint;
  sql          text;
  fqname  text;
BEGIN
  FOR rec in EXECUTE 'select relname from pg_class where relkind = ''S''
                      and relnamespace = (select oid from pg_namespace
                      where nspname=''' || namespace || ''')' LOOP
    fqname :=  namespace || '.' ||  rec.relname;
    IF starteven THEN
      EXECUTE 'SELECT ((last_value / 2) * 2) + 2 from ' || fqname INTO startval;
    ELSE
      EXECUTE 'SELECT ((last_value / 2) * 2) + 1 from ' || fqname INTO startval;
    END If;
    sql := 'ALTER SEQUENCE ' || fqname || ' INCREMENT BY 2 RESTART WITH ' || startval;
    EXECUTE sql;
    RAISE NOTICE '%', sql;
  END LOOP;
  RETURN 'OK';
END;
$$ LANGUAGE plpgsql STRICT;
SELECT adjust_seqs('public', true);  -- in master1 (even)
SELECT adjust_seqs('public', false); -- in master2 (odd)
</pre><p><br />
</p>
<pre class='brush: sql'>-- update sequences that have gotten out-of-sync with the
-- PK field for which they normally provide the default
CREATE OR REPLACE FUNCTION adjust_seqs(namespace text)
  RETURNS text AS $$
DECLARE
  rec           record;
  startval     bigint;
  sql            text;
  seqname  text;
BEGIN
  FOR rec in EXECUTE 'select table_name, column_name, column_default
                      from information_schema.columns
                      where table_schema = ''' || namespace || '''
                      and column_default like ''nextval%''' LOOP

    seqname := pg_get_serial_sequence(rec.table_name, rec.column_name);
    sql := 'select max(' || rec.column_name || ') + 1 from ' || rec.table_name;
    EXECUTE sql INTO startval;
    IF startval IS NOT NULL THEN
      sql := 'ALTER SEQUENCE ' || seqname || ' RESTART WITH ' || startval;
      EXECUTE sql;
      RAISE NOTICE '%', sql;
    END IF;
  END LOOP;
  RETURN 'OK';
END;
$$ LANGUAGE plpgsql STRICT;
select adjust_seqs('public');
</pre><p></p>

<p>Neither of these is heavily tested, and both make certain assumptions, so please test and modify to suit your own needs. Caveat emptor!</p>]]>
        
    </content>
</entry>

<entry>
    <title>[Tip] PostgreSQL Tip of the Day - loading a PostGIS database dump</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/07/postgresql-tip-of-the-day---loading-a-postgis-database-dump.html" />
    <id>tag:blog.credativ.com,2010:/en//2.179</id>

    <published>2010-07-07T01:10:01Z</published>
    <updated>2010-12-07T12:44:00Z</updated>

    <summary>I was given a Postgres database dump to analyze today created by &quot;pg_dump -Fc&quot;. The source database included PostGIS 1.3.x extensions. I&apos;m not sure if this is standard with PostGIS, but the related database objects were all dumped with a...</summary>
    <author>
        <name>Joe Conway</name>
        <uri>http://www.credativ.us</uri>
    </author>
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="PostgreSQL" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Tip" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="postgis" label="PostGIS" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="postgresql" label="PostgreSQL" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p>I was given a Postgres database dump to analyze today created by "pg_dump -Fc". The source database included PostGIS 1.3.x extensions. I'm not sure if this is standard with PostGIS, but the related database objects were all dumped with a hard-coded library path, specifically <tt>/usr/lib/postgresql/8.3/lib</tt>. On my machine, I have many PostgreSQL clusters (essentially at least one for every supported branch dating back to 7.3.x), but they are not located under <tt>/usr/lib/postgresql</tt>.</p>

<p>As such, I needed a quick fix. To wit:<br />
</p>
<pre class='brush: sql'>pg_restore database.with.postgis.tgz &gt; db.w.postgis.dmp
sed 's|/usr/lib/postgresql/8.3/lib|$libdir|g' &lt; db.w.postgis.dmp &gt; db.w.postgis.dmp.new
</pre><p></p>

<p>The first line extracts the dump file from the compressed "custom" format into a human readable text SQL file. The second line replaces the hard-coded library path with the special PostgreSQL $libdir variable. This will always point to the correct location for any given PostgreSQL cluster. You can always discover where this is by running:<br />
<pre>pg_config --libdir</pre></p>]]>
        
    </content>
</entry>

<entry>
    <title>[Howto] Code templates in vim</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/06/howto-code-templates-in-vim.html" />
    <id>tag:blog.credativ.com,2010:/en//2.145</id>

    <published>2010-06-07T09:25:00Z</published>
    <updated>2010-06-07T09:19:36Z</updated>

    <summary>The text editor vim offers several tools for automation. This howto describes a way to auto-include text modules when creating new files. Often during programming or administration you need the same text modules again and again. The editor vim is...</summary>
    <author>
        <name>Martin Zobel-Helas</name>
        <uri>http://www.credativ.de</uri>
    </author>
    
        <category term="Howto" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Linux" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
    <category term="automation" label="automation" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="howto" label="howto" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="linux" label="Linux" scheme="http://www.sixapart.com/ns/types#tag" />
    <category term="vim" label="vim" scheme="http://www.sixapart.com/ns/types#tag" />
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="bash.png" src="/de/static/bash.png" width="90" height="72" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><em>The text editor <tt>vim</tt> offers several tools for automation. This howto describes a way to auto-include text modules when creating new files.</em></p>

<p>Often during programming or administration you need the same text modules again and again. The editor <tt>vim</tt> is very helpful here, as it can detect a file type while it is being created and insert pre-defined text modules accordingly. This behaviour can be configured in the file <tt>.vim/plugin/autoinsert.vim</tt>, for example with:<br />
</p>
<pre class='brush: plain'>
if has(&quot;autocmd&quot;)
augroup autoinsert
  au!
  autocmd BufNewFile *.c call s:Template(&quot;c&quot;)
  autocmd BufNewFile Makefile call s:Template(&quot;make&quot;)
  autocmd BufNewFile makefile call s:Template(&quot;make-simple&quot;)
augroup END
endif

function s:Template(argument)
        if (a:argument == &quot;help&quot;)
                echo &quot;Currently available templates:&quot;
                echo &quot; c                - Plain C Template&quot;
                echo &quot; make             - Makefile Template&quot;
                echo &quot; make-simple      - Simple Variant of the Makefile Template&quot;
        else
                &quot; First delete all in the current buffer
                %d

                &quot; The Makefile variants
                if (a:argument == &quot;make&quot;)
                        0r ~/.vim/skeletons/template.make
                        set ft=make
                elseif (a:argument == &quot;make-simple&quot;)
                        0r ~/.vim/skeletons/template.make_simple
                        set ft=make
                elseif (a:argument == &quot;make-simple-cpp&quot;)
                        0r ~/.vim/skeletons/template.make_simple_cpp
                        set ft=make

                &quot; Stuff for plain C
                elseif (a:argument == &quot;c&quot;)
                        0r ~/.vim/skeletons/template.c
                        set ft=c
                endif

                silent %!~/.vim/do_header %
        endif
endfunction

command! -nargs=1 Template call s:Template(&lt;f-args&gt;)
</pre><p></p>

<p>The lines 21-35 clearly show the template names and include the text modules. The template for <tt>make_simple</tt>, <tt>~/.vim/skeletons/template.make_simple</tt>, for example includes the compiler flags for building C/C++ programs with gcc:</p>
<pre class='brush: plain'>
CC := gcc
CFLAGS := -Wall -pedantic -O3
LDFLAGS :=

PROG := main
OBJS := main.o

all: $(PROG)

$(PROG): $(OBJS)
        $(CC) $(LDFLAGS) -o $@ $^

clean:
        rm -rf $(PROG) $(OBJS)

.PHONY: all clean
</pre><p></p>

<p>Another template is shown below: <tt>~/.vim/skeletons/template.c</tt> includes text modules for not only the obligatory GPL header but also includes a basic code structure:</p>
<pre class='brush: c'>
/*
 * %%FILENAME%% - description
 *
 * Copyright (C) %%YEAR%% %%AUTHOR%%
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.
 */

#include &lt;stdio.h&gt;

int
main (int argc, char **argv)
{
  return 0;
}

/**This must remain at the end of the file.**********
 * vim600:set sw=2 ts=8 fdm=marker fmr=«««,»»»:     *
 * vim600:set cindent cinoptions={1s,&gt;2s,^-1s,n-1s: *
 ****************************************************/
</pre><p><br />
Variables like <tt>%%FILENAME%%</tt> or <tt>%%AUTHOR%%</tt> can also automatically be replaced by a small shell script running during file creation: the script <tt>~/.vim/do_header</tt> labelled with the file name as argument detects the full name with <tt>getent</tt> or <tt>/etc/passwd</tt>, respectively. Other variables are gathered using the default GNU tools as the listing shows:</p>
<pre class='brush: plain'>
#!/usr/bin/env zsh

if which getent &gt; /dev/null; then
        REALNAME=$(getent passwd $USER|awk -F : '{print $5}' | awk -F , '{print $1}')
else
        REALNAME=$(grep $USER /etc/passwd|awk -F : '{print $5}' | awk -F , '{print $1}')
        if which nidump &gt; /dev/null &amp;&amp; [ -z &quot;$REALNAME&quot; ]; then
                REALNAME=$(nidump passwd / | grep $USER|awk -F : '{print $8}')
        fi
fi
DATE=$(date)
YEAR=$(date +%Y)
FILENAME=$(echo $1 | sed 's/[^/]*\///')
FILE=$(echo $FILENAME | sed 's/\..*//')
FILEBIG=$(echo $FILE | tr '[:lower:]' '[:upper:]')
sed     &quot;s/%%AUTHOR%%/$REALNAME/g;
        s/%%DATE%%/$DATE/g;
        s/%%YEAR%%/$YEAR/g;
        s/%%FILENAME%%/$FILENAME/g;
        s/%%FILE%%/$FILE/g;
        s/%%FILEBIG%%/$FILEBIG/g;&quot;
</pre><p><br />
Besides the examples shown here other templates can be generated to deal with HTML files, python or whatnot, among others - the possibilities are endless.</p>

<p>This howto has just touched on one small aspect of the many <a href="http://www.vim.org/vimscriptlinks.php">automations possible with vim</a>. You can find other howtos in this blog in the <a href="/en/howto/">howtos</a> category, which has its own feed - if you need more in-depth <a href="http://www.credativ.co.uk/home/services/support/">support or services for GNU tools or Linux</a>, you've come to the right place at credativ.</p>]]>
        
    </content>
</entry>

<entry>
    <title>[Howto] RHCS: install on Debian</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/05/howto-rhcs-install-on-debian.html" />
    <id>tag:blog.credativ.com,2010:/en//2.148</id>

    <published>2010-05-20T10:40:00Z</published>
    <updated>2010-05-25T10:10:26Z</updated>

    <summary>Following our earlier introduction to RHCS we now present a real world example: the installation of RHCS with Debian to provide certain virtual machines as services. Our RHCS overview already explained the basics of RHCS. This time we will take...</summary>
    <author>
        <name>Roland Wolters</name>
        <uri>http://www.credativ.de</uri>
    </author>
    
        <category term="Debian" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Howto" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Linux" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="RHEL/CentOS" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="tux.jpg" src="/de/static/tux.jpg" width="86" height="102" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><em>Following our earlier introduction to RHCS we now present a real world example: the installation of RHCS with Debian to provide certain virtual machines as services.</em></p>

<p>Our <a href="/en/2010/03/rhcs-an-introduction.html">RHCS overview</a> already explained the basics of RHCS. This time we will take two hosts with shared storage and provide KVM guests as services.</p>

<h3>Installation of the nodes</h3>
In this setup the nodes are the machines which are running KVM. Each running KVM guest is a service managed by RHCS. While installing the KVM hosts you should make sure you comply with the following suggestions:
<ul><li><tt>/tmp/</tt> and <tt>/var/</tt> should be running on different partitions, this improves performance.</li>
<li>Activate Debian backports, especially for the Kernel.</li>
<li>Make sure all IP addresses can be resolved in both directions - <tt>/etc/hosts</tt> helps here in worst case.</li>
<li>The host name must not resolve to <tt>127.0.0.1</tt>! You would only get problems with the Cluster Management System CMAN.</li>
<li><tt>/etc/hosts/</tt> and <tt>/etc/resolv.conf</tt> should be the same on all nodes.</li>
<li>Create password free ssh keys for all nodes and distribute them.</li>
<li>For ultimate performance it is best to install the latest Debian Linux kernel. In our example we used <tt>linux-image-2.6.32-bpo.2-amd64</tt>, which crashes the guest kernels >= 2.6.30. However, a patch is available, see <a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=573071">bug #573071</a>.</li>
<li>The network devices should be named in a way that makes sense, for example: <tt>rhcs-backbone</tt> and <tt>external</tt> instead of <tt>eth0</tt> and <tt>eth1</tt>.</li></ul>

<h3>Configuring the shared storage</h3>
As with almost any HA solution, a key element of RHCS is the shared storage which is accessed by all the nodes. In this example we take a "private" machine and install an iSCSI target on it:
<pre class='brush: plain'>
apt-get install iscsitarget iscsitarget-source 
echo 'ISCSITARGET_ENABLE=true' &gt; /etc/default/iscsitarget
m-a a-i iscsitarget
</pre><p><br />
Keep in mind that the iSCSI target must build properly, see <a href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=566740">bug #566740</a>. The configuration of the shared storage is done via <tt>/etc/ietd.conf</tt>:</p>
<pre class='brush: plain'>
IncomingUser discovery_in YourSecurePwd1
OutgoingUser discovery_out YourSecurePwd2
Target YOURMACHINE:clvm1
       IncomingUser node_in YourSecurePwd1
       OutgoingUser node_out YourSecurePwd2
       Lun 0 Path=/dev/sdx1,Type=blockio
</pre><p><br />
On the nodes the same target must be accessed, so make sure <tt>/etc/iscsi/iscsid.conf</tt> is correct:</p>
<pre class='brush: plain'>
discovery.sendtargets.auth.authmethod = CHAP
discovery.sendtargets.auth.username = discovery_in
discovery.sendtargets.auth.password = YourSecurePwd1
discovery.sendtargets.auth.username_in = discovery_out
discovery.sendtargets.auth.password_in = YourSecurePwd2
node.startup = automatic
node.session.auth.authmethod = CHAP
node.session.auth.username = node_in
node.session.auth.password = YourSecurePwd1
node.session.auth.username_in = node_out
node.session.auth.password_in = YourSecurePwd2
</pre><p><br />
The service is started with <tt>/etc/init.d/open-iscsi start</tt>. Existing targets can be searched, deleted or added by the following commands:</p>
<pre class='brush: plain'>
# discovering the targets
iscsiadm -m discovery -t st -p YOURMACHINE -P 1
# deleting target on wrong interface
iscsiadm -m node -p 192.168.0.100:3260,1 -o delete
# opening the portal
iscsiadm -m node --targetname &quot;iqn.2010-03.YOURMACHINE:clvm1&quot; --portal &quot;YOURMACHINE:3260&quot; --</pre><p></p>

<h3>VM setup</h3>
The virtual machines are provided by KVM. Thus the apropriate KVM software must be installed first:
<pre class='brush: plain'>
apt-get install linux-image-2.6.32-bpo.2-amd64 kvm libvirt-bin virtinst -t lenny-backports
</pre><p><br />
When configuring the bridge, make sure that the bridge name is the same on all nodes. Also the libvirt configuration must be the same on all hosts, so it makes sense to use <a href="/en/2010/03/howto-introduction-to-puppet.html">puppet</a> or similar techniques.<br />
Afterwards, bring up the guests with:</p>
<pre class='brush: plain'>
virt-install -n &lt;NAME&gt; -r 256 --vcpus=1 --disk path=/dev/vg_cluster#/&lt;LV&gt; \
  -c /root/debian-&lt;VERSION&gt;-amd64-netinst.iso --vnc --noautoconsole --os-type linux \
  --os-variant debianLenny --accelerate --network=bridge:bridge0 --hvm -k de
</pre><p><br />
To monitor the process use <tt>virt-viewer -c qemu+ssh://<node>:<port>/system <NAME></tt>.</p>

<h3>RHCS setup</h3>
The next step is the setup of RHCS itself. Again, first things first, the software: <tt>apt-get install redhat-cluster-suite</tt>. This pulls quite a number of services which are not needed in our example:
<pre class='brush: plain'>
invoke-rc.d nfs-kernel-server stop
invoke-rc.d nfs-common stop
invoke-rc.d portmap stop
update-rc.d -f nfs-kernel-server remove
update-rc.d -f nfs-common remove
update-rc.d -f portmap remove
</pre><p><br />
Btw., <tt>system-config-cluster</tt> is not available for Lenny, but our Philipp Hübner has created a backport:</p>
<pre class='brush: plain'>
wget --no-check-certificate https://www.credativ.com/~phu/lenny-backports/system-config-cluster/system-config-cluster_1.0.53-1_all.deb
dpkg -i system-config-cluster_1.0.53-1_all.deb
apt-get -f install
apt-get install xauth
</pre><p><br />
In order to have locking on the LVM cluster, you now need to modify <tt>/etc/lvm/lvm.conf</tt>: check for the <tt>global</tt> part.</p>
<pre class='brush: plain'>
 locking_type = 3
</pre><p><br />
With the newer kernels the module <tt>lock_dlm</tt> also vanished, so CMAN init script must be modified: comment out the line <tt>modprobe lock_dlm 2>&1 || return 1</tt>. Additionally, RHCS 2 only supports XEN, so for libvirt you need to load the resource handler  <tt>vm.sh</tt>.</p>
<pre class='brush: plain'>
wget --no-check-certificate https:///www.credativ.com/~phu/vm.sh -O /usr/share/cluster/vm.sh
chmod +x /usr/share/cluster/vm.sh
</pre><p></p>

<p>RHCS itself is called via</p>
<pre class='brush: plain'>
/etc/init.d/cman start
/etc/init.d/clvm start
/etc/init.d/rgmanager start
</pre><p></p>

<h3>Fencing</h3>
Fencing describes the automagical neutralization of nodes which cease to function properly. In our example we use a power plug which can be controlled via network, NETIO-230A. Currently there is no real fence agent available for the device, but the python library <a href="http://github.com/pklaus/netio230a">Python-Bibliothek</a> offers the necessary background to quickly write one.

<h3>Closing words</h3>
This howto has shown the setup of RHCS on Debian in easy steps - but of course, the correct steps depend very much on the targeted services, so this is just an example. If you need help just ask - <a href="http://www.credativ.co.uk/services/support/projects/high-availability-clustering/">Open Source HA solutions</a> are our speciality, and <a href="http://www.credativ.co.uk/services/support/projects/virtualisation/kvm/">we offer services and support  for KVM virtualization</a> as part of our day to day business.]]>
        
    </content>
</entry>

<entry>
    <title>credativ Training at Munich Open Source School</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/05/credativ-training-at-munich-open-source-school.html" />
    <id>tag:blog.credativ.com,2010:/en//2.160</id>

    <published>2010-05-05T14:00:12Z</published>
    <updated>2010-07-08T11:27:22Z</updated>

    <summary>In May, Consultants from credativ GmbH will be holding a 3 day advanced system and network administration workshop at the Open Source School in Munich. Training specifics (subject to modifications!): Kerberos: This training covers the Kerberos authentification protocol, which can...</summary>
    <author>
        <name>Michael Banck</name>
        
    </author>
    
        <category term="News" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Security" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="credativ" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><em>In May, Consultants from credativ GmbH will be holding a 3 day advanced system and network administration workshop at the <a href="http://www.opensourceschool.de/">Open Source School</a> in Munich.</em></p><br />
Training specifics (subject to modifications!):<br />
<ul><br />
<li><b><a href="http://www.opensourceschool.de/kurse/muenchen/schulung/kerberos/">Kerberos:</a></b> This training covers the Kerberos authentification protocol, which can handle a range of services and operating systems transparently. The use of tickets makes single-sign-in possible; so a user can access all services with a unique log in.  The training will be aimed at network and system administrators who wish to roll out Kerberos in their business or administrative network; it will also cover the installation and management of Kerberos, as well as the integration of services and client programs. <br />
<p><br />
When: <a href="http://www.opensourceschool.de/kurstermine/muenchen/schulung/kerberos-5-2010/">03-05/05/2010</a> and <a href="http://www.opensourceschool.de/kurstermine/muenchen/schulung/kerberos-09-2010/">13-15/09/2010</a></p>

<p><li><b><a href="http://www.opensourceschool.de/kurse/muenchen/schulung/spam-und-virenabwehr/">Spam and Virus Defense:</a></b> This training will clarify the integration and fine tuning of open source based services Postfix, Amavis and SpamAssassin, which protect a network from unnecessary strain due to spam mail or malware. This training will be geared at administrators who wish to secure their company's email systems against spam and viruses.<br />
<p><br />
When: <a href="http://www.opensourceschool.de/kurstermine/muenchen/schulung/spam-und-virenabwehr-05-2010/">26-28/05/2010</a> and <a href="http://www.opensourceschool.de/kurstermine/muenchen/schulung/spam-und-virenabwehr-10-2010/">18-20/10/2010</a></p>

<p><li><b><a href="http://www.opensourceschool.de/kurse/muenchen/schulung/samba-in-heterogenen-netzen/">Samba in heterogenous networks:</a></b> This training concerns Samba as a replacement for Windows servers for smooth integration for both Windows clients in unix-based networks, and Linux servers in Windows-based networks.  The training is directed at administrators wanting to migrate a Windows network completely or partly to Linux with the help of Samba.  The goal of the training is the management and administration of LDAP-based primary/backup domain controller setups.<br />
<p><br />
When: <a href="http://www.opensourceschool.de/kurstermine/muenchen/schulung/samba-06-2010/">30/06-02/07/2010</a><br />
</ul></p>

<p>The training will take place at the Open Source School in Munich city centre, <a href="http://www.opensourceschool.de/ort-anreise/">Amalienstrasse 77</a>. Applications can be made via the Open Source School website or by <a href="http://www.opensourceschool.de/fileadmin/oss_website/downloads/oss_anmeldung.pdf">faxing this form</a>. For further information contact <a href="mailto:Michael Banck <michael.banck@credativ.de>">Michael Banck</a>.
</p>
<p>Further dates for your diary: 21-23 April - <a href="http://www.linuxhotel.de/kurs/postgresql/">PostgreSQL training</a> will be carried out by credativ experts at the Linuxhotel <a href="http://www.linuxhotel.de">Linuxhotel</a> in Essen.
</p>]]>
        
    </content>
</entry>

<entry>
    <title>[Howto] Language based rewrites with Lighttpd and mod_magnet</title>
    <link rel="alternate" type="text/html" href="http://blog.credativ.com/en/2010/04/tip-language-based-rewrites-with-lighttpd-and-mod-magnet.html" />
    <id>tag:blog.credativ.com,2010:/en//2.134</id>

    <published>2010-04-12T09:09:22Z</published>
    <updated>2010-05-05T13:56:12Z</updated>

    <summary>Lighttpd is a web server with a fast growing user base. This howto will demonstrate how redirects can be done based on the language of the user&apos;s browser. While migrating from our old blogging software to Movable Type we decided...</summary>
    <author>
        <name>Bernd Zeimetz</name>
        
    </author>
    
        <category term="Howto" scheme="http://www.sixapart.com/ns/types#category" />
    
        <category term="Open Source" scheme="http://www.sixapart.com/ns/types#category" />
    
    
    <content type="html" xml:lang="en" xml:base="http://blog.credativ.com/en/">
        <![CDATA[<p><img alt="light_logo_170px.png" src="/en/static/light_logo_170px.png" width="100" height="80" class="mt-image-right" style="float: right; margin: 0 0 20px 20px;" /><em>Lighttpd is a web server with a fast growing user base. This howto will demonstrate how redirects can be done based on the language of the user's browser.</em> </p>

<p>While migrating from our old blogging software to <a href="http://www.movabletype.org/opensource/">Movable Type</a> we decided it would be a good idea to show the blog's welcome message in English or German depending on the language setting of the user's browser. Since one of the reasons for the switch to the new blog engine was that Movable Type creates static html pages, we avoided cgi scripts or similar workarounds.</p>

<p>We are using <a href="http://www.lighttpd.net/">Lighttpd</a> to serve all pages, which means that our best option was the mighty <a href="http://redmine.lighttpd.net/wiki/1/Docs:ModMagnet">mod_magnet</a> module. This allows you to control request handling within Lighttpd by running <a href="http://www.lua.org/">Lua</a> scripts, which are able to modify most aspects of the way a request is handled. <a href="http://blog.credativ.com/">http://blog.credativ.com/</a> is now rewritten to the file in the correct language with the help of the following Lua snippet:<br />
</p>
<pre class='brush: lua'>
-- - make sure to configure the script here -----------------------------

language_targets = {}
language_targets[&quot;en&quot;] = &quot;/en/index.html&quot;
language_targets[&quot;de&quot;] = &quot;/de/index.html&quot;
default_language = &quot;en&quot;


-- - nothing to customize below this line -------------------------------
--

--[[ string:split function taken from http://lua-users.org/wiki/SplitJoin
      Thanks to Joan Ordinas
  ]]      
function string:split(sSeparator, nMax, bRegexp)
    assert(sSeparator ~= '')
    assert(nMax == nil or nMax &gt;= 1)

    local aRecord = {}

    if self:len() &gt; 0 then
        local bPlain = not bRegexp
        nMax = nMax or -1

        local nField=1 nStart=1
        local nFirst,nLast = self:find(sSeparator, nStart, bPlain)
        while nFirst and nMax ~= 0 do
            aRecord[nField] = self:sub(nStart, nFirst-1)
            nField = nField+1
            nStart = nLast+1
            nFirst,nLast = self:find(sSeparator, nStart, bPlain)
            nMax = nMax-1
        end
        aRecord[nField] = self:sub(nStart)
    end

    return aRecord
end

--[[ Based on trim14 from http://lua-users.org/wiki/StringTrim ]]
do
    require 're'
    require 'lpeg'

    local ptrim = re.compile&quot;%s* {(%s* %S+)*}&quot;
    local match = lpeg.match
    function string:trim()
        return match(ptrim, self)
    end
end


lang_header = lighty.request['Accept-Language']
lighty.env[&quot;uri.path&quot;] = language_targets[default_language]
if (lang_header) then
    lang_header = string.lower(lang_header)
    local lang_order = {}
    for i, language in ipairs(string.split(lang_header, &quot;,&quot;)) do
        language_configs = string.split(language, &quot;;&quot;)
        language = string.trim(language_configs[1])
        table.remove(language_configs, 1)
        if     ((#language == 2) and string.find(language, &quot;[a-z][a-z]&quot;))
            or ((#language == 5) and string.find(language, &quot;[a-z][a-z][-][a-z][a-z]&quot;))
        then
            local q = 1
            for i, config in ipairs(language_configs) do
                local config_data = string.split(config, &quot;=&quot;)
                if (#config_data == 2) then
                    local lvalue = string.trim(config_data[1])
                    local rvalue = string.trim(config_data[2])
                    if lvalue == &quot;q&quot; then
                        q = tonumber(rvalue)
                    end
                end
            end
            table.insert(lang_order, {language, q}) 
        end
    end
    table.sort(lang_order, function(a,b) return (a[2] &gt; b[2]) end)
    for i,v in ipairs(lang_order) do
        local lang = string.split(v[1], '-')[1]
        if language_targets[lang] then
            lighty.env[&quot;uri.path&quot;] = language_targets[lang]
            break
        end
    end
end

lighty.env[&quot;physical.rel-path&quot;] = lighty.env[&quot;uri.path&quot;]
lighty.env[&quot;physical.path&quot;] = lighty.env[&quot;physical.doc-root&quot;] .. lighty.env[&quot;physical.rel-path&quot;]
</pre><p></p>

<p>Of course, the Lighttpd configuration has to include <tt>mod_magnet</tt>. To actually rewrite any request to "/" the configuration must also include the following snippet:<br />
</p>
<pre class='brush: perl'>
$HTTP[&quot;url&quot;] =~ &quot;^/$&quot; {
	magnet.attract-physical-path-to = ( &quot;/path/to/your/script.lua&quot; )
}
</pre><p></p>

<p><tt>mod_magnet</tt> caches the compiled script and executes it within the core of Lighttpd so it shouldn't introduce any noticeable delay in the delivery of your webpages.</p>

<p><strong>Update:</strong> Some people asked for a script to parse the full Accepted-Language header. Although this was not really an issue for us as the two blogs are independent and people have to check which blog to read in any case, I've updated the script to parse the header properly. Also it should be easier to re-use for your own needs now.</p>]]>
        
    </content>
</entry>

</feed>

