<?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>Infrastructure Archives | Clever Cloud</title>
	<atom:link href="https://www.clever.cloud/blog/tag/infrastructure/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.clever.cloud/blog/tag/infrastructure/</link>
	<description>From Code to Product</description>
	<lastBuildDate>Fri, 20 Mar 2026 14:50:35 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://cdn.clever-cloud.com/uploads/2023/03/cropped-cropped-favicon-32x32.png</url>
	<title>Infrastructure Archives | Clever Cloud</title>
	<link>https://www.clever.cloud/blog/tag/infrastructure/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>How We Cut Latency Down by 30k% on Our Git Server</title>
		<link>https://www.clever.cloud/blog/engineering/2015/06/09/git-server-30k-improvement/</link>
		
		<dc:creator><![CDATA[Marc-Antoine Perennou]]></dc:creator>
		<pubDate>Tue, 09 Jun 2015 14:01:00 +0000</pubDate>
				<category><![CDATA[Engineering]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[performances]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2015/06/09/git-server-30k-improvement/</guid>

					<description><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="ars perfs 1" decoding="async" fetchpriority="high" srcset="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1368x528.jpg 1368w" sizes="(max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, git is core in the deployment process. With the years, our needs evolved, especially in terms of performance. This is how we dealt with it.</p>
<span id="more-2800"></span>

<h3 id="a-bit-of-background-first">A bit of background first</h3>
<p>When we started Clever Cloud, we chose to use <a href="http://gitolite.com/gitolite/index.html">gitolite</a> to manage our git repositories. It appeared to be a complete and functional solution. We used it internally first, for managing our own internal repositories even when the product wasn&#39;t released yet.</p>
<p>After several months of testing, we were convinced that it was a really good solution, and chose to go with it.</p>
<h4 id="managing-gitolite-configuration">Managing gitolite configuration</h4>
<p>gitolite is primary designed to be configured manually by a sysadmin. You have to describe every user, group of users and repositories in configuration files. Gitolite will then use these files to generate its internal stuff for dealing with access rights. Gitolite ensures repositories are created and hooks propagated.</p>
<p>We were in the need of automatic reconfiguration, for quite obvious reasons. We therefore developed a tool called <code>etilotig</code> which aim was to keep gitolite&#39;s configuration up to date. On startup, this tool would load its initial configuration from the API and then listen to <a href="https://www.amqp.org/">AMQP</a> events to update its configuration cache and write the new gitolite configuration accordingly.</p>
<p>It worked actually quite well for longer than we expected, and we used it in production until May 5th 2015.</p>
<h3 id="the-drawbacks-of-gitolite">The drawbacks of gitolite</h3>
<p>gitolite was great but had a few major drawbacks we weren&#39;t happy with.</p>
<ul>
<li>as previously said, it wasn&#39;t meant to be dynamically configurable, which required some non-trivial hacks</li>
<li>it required duplicating the configuration in both the API and gitolite itself</li>
<li>all the repositories were created in a same directory</li>
<li>at each repository creation, it did a full pass on all the repositories to check whether the hooks were up to date
or not</li>
<li>rewriting only part of its configuration wasn&#39;t trivial at all so we ended up rewriting most of it for each change</li>
</ul>
<p>Those problems were annoying but not critical at the beginning, but some of them became quite interesting to us.</p>
<p>The fact that all repositories are created in a same directory is a huge performance issue when the number of repositories become really high.</p>
<p>We actually dropped the part that checks for the hooks at each repository creation from the gitolite code a while back as it took half the time of the gitolite internal configuration regeneration on update.</p>
<h3 id="the-new-etilotig">The new etilotig</h3>
<p>While gitolite used to be efficient, lately it had a lot of performance problems, and depending on the timing of the events, it could take up to five (!) minutes to create a new repository. This went far beyond our acceptable limits, so we had to find another solution.</p>
<p>The idea was simple: drop gitolite totally and improve our configuration management tool etilotig to do what was needed by itself.</p>
<p>The checklist we needed to accomplish was quite tiny:</p>
<ul>
<li>ssh keys management</li>
<li>authorization management</li>
<li>repositories creation</li>
<li>hooks installation</li>
</ul>
<h4 id="ssh-keys-management">Ssh keys management</h4>
<p>When its goal was only to manage the gitolite configuration, etilotig only forwarded them to gitolite, which in turn handled them. Now, we have to manage the <code>authorized_keys</code> file by ourselves.</p>
<p>We basically write a new one each time an ssh key is added or removed and then replace the old one with the new one.</p>
<p>Each line is printed as such:</p>
<pre><code class="language-text">command=&quot;AUTH_SCRIPT USER_ID&quot;,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty PUBLIC_KEY
</code></pre>
<p>With <code>AUTH_SCRIPT</code> pointing to the authorization script that I&#39;ll speak of later, <code>USER_ID</code> being the user id of the key owner and <code>PUBLIC_KEY</code> being their public key.</p>
<p>The authorization script will thus be called with the user id as first parameter.</p>
<p>That solves the first point of our TODO list.</p>
<h4 id="repositories-management">Repositories management</h4>
<p>At startup, etilotig writes some bash configuration files defining basic things such as the directory in which repositories have to be created.</p>
<p>Then we have a tiny bash script in charge of the repository creation. We now create them in a deeper directory hierarchy to get as few repositories as possible per directory. Say we had <code>/data/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> before, we now have <code>/data/app_18/c6/02/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> which makes things waaaaay faster.</p>
<pre><code class="language-bash">#!/bin/bash

create_repo() {
local repo_dir=&quot;${1}&quot;

mkdir -p &quot;${repo_dir}&quot;
pushd &quot;${repo_dir}&quot; &amp;&gt;/dev/null
git init --bare
popd &amp;&gt;/dev/null
}

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

[[ -d &quot;${repo_dir}&quot;/hooks ]] || create_repo &quot;${repo_dir}&quot;
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>Then we have another one for hooks installation.</p>
<pre><code class="language-bash">#!/bin/bash

shopt -s nullglob

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

for hook in ${HOME}/.etilotig/hooks/*; do
ln -sf &quot;${hook}&quot; &quot;${repo_dir}&quot;/hooks/
done
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>With those two simple scripts, we only have to call them for each repository at startup to ensure everything is OK, and at each repository creation, which solves two of the four points from our TODO list, only one left.</p>
<h4 id="authorization">Authorization</h4>
<p>Now, the goal was <em>not</em> to duplicate the configuration anymore, but rather use the configuration from the API, thus externalising the whole thing. Dropping all the configuration management from etilotig reduced its size by more than 50%.</p>
<p>The way etilotig manages authorization is quite simple: when it generates its internal configuration, it actually generates a perl script which is called on each ssh connection attempt. The script then authorises or not the transaction.</p>
<p>We made a similar script which prints the users some information about which repositories they have access to if they just run <code>ssh git@push.par.clever-cloud.com</code> or such, checks if they are authorized when they try to git push/pull or rejects any other request.</p>
<p>It looks like this (with some extra stuff added):</p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    if [[ -z &quot;${SSH_CONNECTION}&quot; ]]; then
        echo &quot;Who the hell are you?&quot; &gt;&amp;2
        exit 1
    fi

if [[ -z &quot;${SSH_ORIGINAL_COMMAND}&quot; ]]; then
        export SSH_ORIGINAL_COMMAND=&quot;info&quot;
fi
}

ask_for_info() {
    local userid=&quot;${1}&quot;

# make the request to the API to retrieve user info message
echo &quot;some info&quot;
}

ask_for_authorization() {
    local userid=&quot;${1}&quot;
    local appid=&quot;${2}&quot;

# make the request and return the HTTP status code here. 200 means authorized.
echo 200
}

authorize() {
    local userid=&quot;${1}&quot;
    local verb=&quot;${2}&quot;
    local appid=&quot;${3}&quot;
    local ret=1
    case &quot;${verb}&quot; in
        &quot;git-receive-pack&quot;|&quot;git-upload-pack&quot;)
            local code
            code=$(ask_for_authorization &quot;${userid}&quot; &quot;${appid}&quot;)
            [[ &quot;${code}&quot; == &quot;200&quot; ]] &amp;&amp; ret=0
            ;;
    esac
    return &quot;${ret}&quot;
}

final_abort() {
    echo &quot;What are you trying to achieve here?&quot; &gt;&amp;2
    exit 2
}
main() {
    sanity_check
    local userid=&quot;${1}&quot;
    local verb
    local repo
    local repo_dir
    verb=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 1)
    repo=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 2 | tr -d &quot;&#39;\&quot;&quot;)
    [[ &quot;${repo}&quot; == /* ]] &amp;&amp; repo=${repo:1}
    repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;
    if [[ &quot;${verb}&quot; == &quot;info&quot; ]]; then
        ask_for_info &quot;${userid}&quot;
    elif authorize &quot;${userid}&quot; &quot;${verb}&quot; &quot;${repo}&quot;; then
        export CC_USER=&quot;${userid}&quot;
        export CC_NOTIFY_SCRIPT=&quot;${HOME}/.etilotig/send-push-event&quot;
        exec &quot;${verb}&quot; &quot;${repo_dir}&quot;
    else
        final_abort
    fi
}
. &quot;${HOME}&quot;/.etilotig/.etilotigrc
main &quot;${@}&quot;
</code></pre>
<p>With this in place, nearly everything was ready. Two tiny hooks on top of that to only allow users to push on the master branch, and to trigger a deployment on git push:</p>
<p><code>hooks/update</code></p>
<pre><code class="language-bash">#!/bin/bash

main() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
    if [[ &quot;${rev}&quot; != &quot;refs/heads/master&quot; ]]; then
        echo &quot;You tried to push to a custom branch.&quot;
        echo &quot;Only master is allowed.&quot;
        exit 1
    fi
}

main &quot;${@}&quot;
</code></pre>
<p><code>hooks/post-update</code></p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
}

main () {
    local rev=&quot;${1}&quot;
    sanity_check &quot;${rev}&quot;
    local repo=$(basename $(pwd))
    local appId=${repo/.git/}
    local commitId=$(git rev-parse &quot;${rev}&quot;)
    &quot;${CC_NOTIFY_SCRIPT}&quot; &quot;${appId}&quot; &quot;${commitId}&quot; &quot;${CC_USER}&quot;
    echo &quot;[SUCCESS] The application has successfully been queued for redeploy.&quot;
}

main &quot;${@}&quot;
</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>That&#39;s it, we have our new git server manager up and running, which works pretty well.</p>
<p>The performance gain? We went from between 3 and more than 5 minutes to less than 1 second per action, while dropping the whole gitolite codebase and reducing the size of etilotig by 50%, with an average performance gain of 30k%.</p>
<p>gitolite has been very useful both in its utilisation and its codebase to better comprehend the whole authentication mechanism, so a great thanks to this awesome tool.</p>
<p>Now gitolite is dead, long live etilotig!</p>
]]></description>
										<content:encoded><![CDATA[<p><img width="1400" height="540" src="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg" class="attachment-post-thumbnail size-post-thumbnail wp-post-image" alt="ars perfs 1" decoding="async" srcset="https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1.jpg 1400w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-300x116.jpg 300w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1024x395.jpg 1024w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-768x296.jpg 768w, https://cdn.clever-cloud.com/uploads/2021/08/ars-perfs-1-1368x528.jpg 1368w" sizes="(max-width: 1400px) 100vw, 1400px" /></p><p>At Clever Cloud, git is core in the deployment process. With the years, our needs evolved, especially in terms of performance. This is how we dealt with it.</p>
<span id="more-2800"></span>

<h3 id="a-bit-of-background-first">A bit of background first</h3>
<p>When we started Clever Cloud, we chose to use <a href="http://gitolite.com/gitolite/index.html">gitolite</a> to manage our git repositories. It appeared to be a complete and functional solution. We used it internally first, for managing our own internal repositories even when the product wasn&#39;t released yet.</p>
<p>After several months of testing, we were convinced that it was a really good solution, and chose to go with it.</p>
<h4 id="managing-gitolite-configuration">Managing gitolite configuration</h4>
<p>gitolite is primary designed to be configured manually by a sysadmin. You have to describe every user, group of users and repositories in configuration files. Gitolite will then use these files to generate its internal stuff for dealing with access rights. Gitolite ensures repositories are created and hooks propagated.</p>
<p>We were in the need of automatic reconfiguration, for quite obvious reasons. We therefore developed a tool called <code>etilotig</code> which aim was to keep gitolite&#39;s configuration up to date. On startup, this tool would load its initial configuration from the API and then listen to <a href="https://www.amqp.org/">AMQP</a> events to update its configuration cache and write the new gitolite configuration accordingly.</p>
<p>It worked actually quite well for longer than we expected, and we used it in production until May 5th 2015.</p>
<h3 id="the-drawbacks-of-gitolite">The drawbacks of gitolite</h3>
<p>gitolite was great but had a few major drawbacks we weren&#39;t happy with.</p>
<ul>
<li>as previously said, it wasn&#39;t meant to be dynamically configurable, which required some non-trivial hacks</li>
<li>it required duplicating the configuration in both the API and gitolite itself</li>
<li>all the repositories were created in a same directory</li>
<li>at each repository creation, it did a full pass on all the repositories to check whether the hooks were up to date
or not</li>
<li>rewriting only part of its configuration wasn&#39;t trivial at all so we ended up rewriting most of it for each change</li>
</ul>
<p>Those problems were annoying but not critical at the beginning, but some of them became quite interesting to us.</p>
<p>The fact that all repositories are created in a same directory is a huge performance issue when the number of repositories become really high.</p>
<p>We actually dropped the part that checks for the hooks at each repository creation from the gitolite code a while back as it took half the time of the gitolite internal configuration regeneration on update.</p>
<h3 id="the-new-etilotig">The new etilotig</h3>
<p>While gitolite used to be efficient, lately it had a lot of performance problems, and depending on the timing of the events, it could take up to five (!) minutes to create a new repository. This went far beyond our acceptable limits, so we had to find another solution.</p>
<p>The idea was simple: drop gitolite totally and improve our configuration management tool etilotig to do what was needed by itself.</p>
<p>The checklist we needed to accomplish was quite tiny:</p>
<ul>
<li>ssh keys management</li>
<li>authorization management</li>
<li>repositories creation</li>
<li>hooks installation</li>
</ul>
<h4 id="ssh-keys-management">Ssh keys management</h4>
<p>When its goal was only to manage the gitolite configuration, etilotig only forwarded them to gitolite, which in turn handled them. Now, we have to manage the <code>authorized_keys</code> file by ourselves.</p>
<p>We basically write a new one each time an ssh key is added or removed and then replace the old one with the new one.</p>
<p>Each line is printed as such:</p>
<pre><code class="language-text">command=&quot;AUTH_SCRIPT USER_ID&quot;,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty PUBLIC_KEY
</code></pre>
<p>With <code>AUTH_SCRIPT</code> pointing to the authorization script that I&#39;ll speak of later, <code>USER_ID</code> being the user id of the key owner and <code>PUBLIC_KEY</code> being their public key.</p>
<p>The authorization script will thus be called with the user id as first parameter.</p>
<p>That solves the first point of our TODO list.</p>
<h4 id="repositories-management">Repositories management</h4>
<p>At startup, etilotig writes some bash configuration files defining basic things such as the directory in which repositories have to be created.</p>
<p>Then we have a tiny bash script in charge of the repository creation. We now create them in a deeper directory hierarchy to get as few repositories as possible per directory. Say we had <code>/data/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> before, we now have <code>/data/app_18/c6/02/app_18c6021b-0860-4f97-a08d-0663f45cf3f0.git</code> which makes things waaaaay faster.</p>
<pre><code class="language-bash">#!/bin/bash

create_repo() {
local repo_dir=&quot;${1}&quot;

mkdir -p &quot;${repo_dir}&quot;
pushd &quot;${repo_dir}&quot; &amp;&gt;/dev/null
git init --bare
popd &amp;&gt;/dev/null
}

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

[[ -d &quot;${repo_dir}&quot;/hooks ]] || create_repo &quot;${repo_dir}&quot;
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>Then we have another one for hooks installation.</p>
<pre><code class="language-bash">#!/bin/bash

shopt -s nullglob

main() {
    local repo=&quot;${1}&quot;
    local repo_dir
    
repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;

for hook in ${HOME}/.etilotig/hooks/*; do
ln -sf &quot;${hook}&quot; &quot;${repo_dir}&quot;/hooks/
done
}

. &quot;${HOME}&quot;/.etilotig/.etilotigrc

main &quot;${@}&quot;
</code></pre>
<p>With those two simple scripts, we only have to call them for each repository at startup to ensure everything is OK, and at each repository creation, which solves two of the four points from our TODO list, only one left.</p>
<h4 id="authorization">Authorization</h4>
<p>Now, the goal was <em>not</em> to duplicate the configuration anymore, but rather use the configuration from the API, thus externalising the whole thing. Dropping all the configuration management from etilotig reduced its size by more than 50%.</p>
<p>The way etilotig manages authorization is quite simple: when it generates its internal configuration, it actually generates a perl script which is called on each ssh connection attempt. The script then authorises or not the transaction.</p>
<p>We made a similar script which prints the users some information about which repositories they have access to if they just run <code>ssh git@push.par.clever-cloud.com</code> or such, checks if they are authorized when they try to git push/pull or rejects any other request.</p>
<p>It looks like this (with some extra stuff added):</p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    if [[ -z &quot;${SSH_CONNECTION}&quot; ]]; then
        echo &quot;Who the hell are you?&quot; &gt;&amp;2
        exit 1
    fi

if [[ -z &quot;${SSH_ORIGINAL_COMMAND}&quot; ]]; then
        export SSH_ORIGINAL_COMMAND=&quot;info&quot;
fi
}

ask_for_info() {
    local userid=&quot;${1}&quot;

# make the request to the API to retrieve user info message
echo &quot;some info&quot;
}

ask_for_authorization() {
    local userid=&quot;${1}&quot;
    local appid=&quot;${2}&quot;

# make the request and return the HTTP status code here. 200 means authorized.
echo 200
}

authorize() {
    local userid=&quot;${1}&quot;
    local verb=&quot;${2}&quot;
    local appid=&quot;${3}&quot;
    local ret=1
    case &quot;${verb}&quot; in
        &quot;git-receive-pack&quot;|&quot;git-upload-pack&quot;)
            local code
            code=$(ask_for_authorization &quot;${userid}&quot; &quot;${appid}&quot;)
            [[ &quot;${code}&quot; == &quot;200&quot; ]] &amp;&amp; ret=0
            ;;
    esac
    return &quot;${ret}&quot;
}

final_abort() {
    echo &quot;What are you trying to achieve here?&quot; &gt;&amp;2
    exit 2
}
main() {
    sanity_check
    local userid=&quot;${1}&quot;
    local verb
    local repo
    local repo_dir
    verb=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 1)
    repo=$(echo &quot;${SSH_ORIGINAL_COMMAND}&quot; | cut -d &#39; &#39; -f 2 | tr -d &quot;&#39;\&quot;&quot;)
    [[ &quot;${repo}&quot; == /* ]] &amp;&amp; repo=${repo:1}
    repo_dir=&quot;${REPOS_DIR}/${repo:0:6}/${repo:6:2}/${repo:8:2}/${repo}&quot;
    if [[ &quot;${verb}&quot; == &quot;info&quot; ]]; then
        ask_for_info &quot;${userid}&quot;
    elif authorize &quot;${userid}&quot; &quot;${verb}&quot; &quot;${repo}&quot;; then
        export CC_USER=&quot;${userid}&quot;
        export CC_NOTIFY_SCRIPT=&quot;${HOME}/.etilotig/send-push-event&quot;
        exec &quot;${verb}&quot; &quot;${repo_dir}&quot;
    else
        final_abort
    fi
}
. &quot;${HOME}&quot;/.etilotig/.etilotigrc
main &quot;${@}&quot;
</code></pre>
<p>With this in place, nearly everything was ready. Two tiny hooks on top of that to only allow users to push on the master branch, and to trigger a deployment on git push:</p>
<p><code>hooks/update</code></p>
<pre><code class="language-bash">#!/bin/bash

main() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
    if [[ &quot;${rev}&quot; != &quot;refs/heads/master&quot; ]]; then
        echo &quot;You tried to push to a custom branch.&quot;
        echo &quot;Only master is allowed.&quot;
        exit 1
    fi
}

main &quot;${@}&quot;
</code></pre>
<p><code>hooks/post-update</code></p>
<pre><code class="language-bash">#!/bin/bash

sanity_check() {
    local rev=&quot;${1}&quot;
    if [[ &quot;${rev}&quot; == refs/tags/* ]]; then
        exit 0
    fi
}

main () {
    local rev=&quot;${1}&quot;
    sanity_check &quot;${rev}&quot;
    local repo=$(basename $(pwd))
    local appId=${repo/.git/}
    local commitId=$(git rev-parse &quot;${rev}&quot;)
    &quot;${CC_NOTIFY_SCRIPT}&quot; &quot;${appId}&quot; &quot;${commitId}&quot; &quot;${CC_USER}&quot;
    echo &quot;[SUCCESS] The application has successfully been queued for redeploy.&quot;
}

main &quot;${@}&quot;
</code></pre>
<h3 id="conclusion">Conclusion</h3>
<p>That&#39;s it, we have our new git server manager up and running, which works pretty well.</p>
<p>The performance gain? We went from between 3 and more than 5 minutes to less than 1 second per action, while dropping the whole gitolite codebase and reducing the size of etilotig by 50%, with an average performance gain of 30k%.</p>
<p>gitolite has been very useful both in its utilisation and its codebase to better comprehend the whole authentication mechanism, so a great thanks to this awesome tool.</p>
<p>Now gitolite is dead, long live etilotig!</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Open Cloud for all</title>
		<link>https://www.clever.cloud/blog/press/2013/01/30/open-cloud-month/</link>
		
		<dc:creator><![CDATA[Clément Nivolle]]></dc:creator>
		<pubDate>Wed, 30 Jan 2013 00:00:00 +0000</pubDate>
				<category><![CDATA[Press]]></category>
		<category><![CDATA[Iliad]]></category>
		<category><![CDATA[Infrastructure]]></category>
		<guid isPermaLink="false">https://www2.cleverapps.io/wp/blog/technology/2013/01/30/open-cloud-month/</guid>

					<description><![CDATA[French version below Official launch of Clever Cloud’s Elastic Web Hosting, free until the 24th of february Nantes, the 30th of January, 2013 —As it officially launches its &#8220;Elastic Web Hosting&#8221; service (EWH), Clever Cloud announces the complete and free access to its cloud platform application (PAAS) until February 24, 2013. This special opening is [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><em>French version below</em></p>
<h3 id="official-launch-of-clever-clouds-elastic-web-hosting-free-until-the-24th-of-february">Official launch of Clever Cloud’s Elastic Web Hosting, free until the 24th of february</h3>
<p>Nantes, the 30th of January, 2013 —As it officially launches its &#8220;Elastic Web Hosting&#8221; service (EWH), Clever Cloud announces the complete and free access to its cloud platform application (PAAS) until February 24, 2013. This special opening is available to all, starting now from the Internet site <a href="https://www.clever.cloud">www.clever.cloud</a></p>
<p><span id="more-2995"></span></p>
<p>After Kima Ventures &#8216;s having taken an equity stake in the company (the investment fund of Jeremie Berrebi and Xavier Niel), Clever Cloud is deploying its innovative multi-language application hosting technology on a large scale.</p>
<p>The EWH solution is not an nth assembly of repackaged proprietary software. The developers of Clever Cloud have done thorough work; no layer was spared in order to attain, independently, a level of performance above that of the competition.</p>
<p>The infrastructure is composed of more than 400 servers, split among two latest-generation datacenters of Iliad Datacenter located in this country. &#8220;It is a matter of great pride for Iliad Datacenter to accompany a project whose growth is so strong and whose flagship product constitutes a real technological break from the market.&#8221; declared Arnaud de Bermingham.</p>
<p>The product natively supports a large number of languages, notably PHP5, Java 5 6 and 7, Scala, MySQL, PgSQL, Ruby, as well as the collaborative development tool GIT. New functions such as Play!, node.js as well as mongoDB are already available in beta. Functions like provisioning and automatic scalability are offered by default and without a surcharge.</p>
<p>As it stands, the &#8220;Elastic Web Hosting&#8221; service responds to today&#8217;s market&#8217;s needs, on infrastructure that is conceived, managed and hosted in France, not subject to the Patriot Act, without having to wait for a hypothetical creation of services announced several months ago by operators who are financed up to hundreds of millions of euros by the French taxpayer.</p>
<p>website: <a href="https://www.clever.cloud">https://www.clever.cloud</a></p>
<p>Contact: <a href="mailto:press@clever-cloud.com">press@clever-cloud.com</a></p>
<hr />
<p><em>French version:</em></p>
<h3 id="lancement-officiel-de-clever-cloud-service-totalement-gratuit-jusquau-24-février">Lancement officiel de Clever Cloud, service totalement gratuit jusqu’au 24 février</h3>
<p>Nantes, le 30 janvier 2013 — A l’occasion du lancement officiel de son service “Elastic Web Hosting” (EWH), Clever Cloud annonce l’accès complet et gratuit à sa plateforme de cloud applicatif (PAAS) jusqu’au 24 février 2013. Cette ouverture exceptionnelle est ouverte à tous dès maintenant depuis le site Internet <a href="http://www.clever.cloud">www.clever.cloud</a></p>
<p>Après l’entrée de Kima Ventures au capital de l’entreprise (le fond d’investissement de Jeremie Berrebi et Xavier Niel), Clever Cloud déploie à très grande échelle sa technologie innovante d’hébergement applicatif multi-langage.</p>
<p>La solution EWH n’est pas un enième assemblage de logiciels éditeurs repackagés. Les développeurs de Clever Cloud ont effectué un travail de fond ; aucune couche n’a été epargnée, afin d’atteindre un niveau de performance au dessus de la concurrence en toute indépendance.</p>
<p>L’infrastructure est composée de plus de 400 serveurs, répartis sur deux datacenters dernière génération de Iliad Datacenter, situés sur le territoire national. “C’est une très grande fierté pour Iliad Datacenter d’accompagner un projet dont la croissance est aussi forte et dont le produit phare constitue une vraie rupture technologique par rapport au marché” déclare Arnaud de Bermingham.</p>
<p>Le produit supporte nativement un grand nombre de langage, notamment PHP5, Java 5 6 et 7, Scala, MySQL, PgSQL, Ruby, ainsi que l’outil de développement collaboratif GIT. De nouvelles fonctionnalités tels que le support de Play! Framework, Node.js ainsi que mongoDB sont à présent disponible en beta. Les fonctionnalités tels que le provisioning et la scalabilité automatique sont proposés par défaut et sans supplément de prix.</p>
<p>En l’état, le service “Elastic Web Hosting” réponds dès aujourd’hui aux besoins du marché, sur des infrastructures conçues, gérées et hébergées en France, non soumises au patriot-act, sans attendre une hypothétique mise en place d’offres annoncées depuis plusieurs mois par les opérateurs financés à hauteur de centaines de millions d’euros par le contribuable français.</p>
<p>Site : <a href="https://www.clever.cloud">https://www.clever.cloud</a></p>
<p>Contact : <a href="mailto:press@clever-cloud.com">press@clever-cloud.com</a></p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
