<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Mikko Kortelainen</title><link href="https://mikko.kortelainen.io/blog/" rel="alternate"></link><link href="https://mikko.kortelainen.io/blog/feeds/all.atom.xml" rel="self"></link><id>https://mikko.kortelainen.io/blog/</id><updated>2026-03-31T06:00:00+03:00</updated><entry><title>Running Claude Code Through GitHub Copilot</title><link href="https://mikko.kortelainen.io/blog/cc-gh-proxy/" rel="alternate"></link><published>2026-03-31T06:00:00+03:00</published><updated>2026-03-31T06:00:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2026-03-31:/blog/cc-gh-proxy/</id><summary type="html">&lt;p&gt;&lt;a href="https://docs.anthropic.com/en/docs/claude-code/overview"&gt;Claude Code&lt;/a&gt; is
Anthropic's CLI tool for working with Claude in the terminal. It's good for
coding tasks, but it requires either a Claude subscription or an Anthropic API
key.&lt;/p&gt;
&lt;p&gt;GitHub copilot also supports Anthropic models. If you already have a GitHub
Copilot subscription, there's a way to use those …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://docs.anthropic.com/en/docs/claude-code/overview"&gt;Claude Code&lt;/a&gt; is
Anthropic's CLI tool for working with Claude in the terminal. It's good for
coding tasks, but it requires either a Claude subscription or an Anthropic API
key.&lt;/p&gt;
&lt;p&gt;GitHub copilot also supports Anthropic models. If you already have a GitHub
Copilot subscription, there's a way to use those models with Claude Code. GitHub
Copilot's API natively supports the Anthropic Messages format, so a thin local
proxy can redirect Claude Code's requests to Copilot instead.&lt;/p&gt;
&lt;p&gt;I wrote &lt;a href="https://github.com/kortsi/cc-gh-proxy"&gt;cc-gh-proxy&lt;/a&gt; for this. It's a
single Python file with no dependencies beyond the standard library.&lt;/p&gt;
&lt;h2&gt;How It Works&lt;/h2&gt;
&lt;p&gt;The proxy sits between Claude Code and &lt;code&gt;api.githubcopilot.com&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Claude&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;localhost&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;api&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;githubcopilot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All it does is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Swap the auth header to a GitHub CLI OAuth token&lt;/li&gt;
&lt;li&gt;Map model names (&lt;code&gt;claude-opus-4-6&lt;/code&gt; becomes &lt;code&gt;claude-opus-4.6&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Strip &lt;code&gt;cache_control&lt;/code&gt; fields that Copilot doesn't support&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No format conversion is needed for the Anthropic Messages path. Token counts and
streaming work natively.&lt;/p&gt;
&lt;p&gt;Copilot also exposes an OpenAI-compatible endpoint, which is used for models
other than Anthropic's, so the proxy translates those responses between OpenAI
and Anthropic formats. This lets you use models like &lt;code&gt;gpt-4&lt;/code&gt; with Claude Code,
albeit without streaming.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;You need the GitHub CLI (&lt;code&gt;gh&lt;/code&gt;) and a Copilot subscription:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gh&lt;span class="w"&gt; &lt;/span&gt;auth&lt;span class="w"&gt; &lt;/span&gt;login
gh&lt;span class="w"&gt; &lt;/span&gt;auth&lt;span class="w"&gt; &lt;/span&gt;refresh&lt;span class="w"&gt; &lt;/span&gt;--hostname&lt;span class="w"&gt; &lt;/span&gt;github.com&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;copilot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then point Claude Code at the proxy by adding this to
&lt;code&gt;.claude/settings.json&lt;/code&gt; in your project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;env&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;ANTHROPIC_BASE_URL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://localhost:4000&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Start the proxy and run Claude Code as usual:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./cc-gh-proxy.py&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
claude
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Token Management&lt;/h2&gt;
&lt;p&gt;The proxy fetches an OAuth token from &lt;code&gt;gh auth token&lt;/code&gt; at startup and refreshes
it automatically every hour. If a request gets a 401, the token is refreshed
immediately and the request retried. This is all thread-safe, so concurrent
Claude Code sessions work fine.&lt;/p&gt;
&lt;h2&gt;Logging&lt;/h2&gt;
&lt;p&gt;The proxy writes structured request logs to &lt;code&gt;logs/requests.jsonl&lt;/code&gt; -- one
JSON object per request with model, messages, token usage, and timing.&lt;/p&gt;
&lt;h2&gt;Caveats&lt;/h2&gt;
&lt;p&gt;Copilot's API doesn't support Anthropic's prompt caching, so the &lt;code&gt;cache_control&lt;/code&gt;
fields are stripped. This means slightly higher latency since nothing is cached
between requests.&lt;/p&gt;
&lt;p&gt;This works today, but GitHub could change or restrict their Copilot API at any
time. The proxy is experimental and may not support every edge case.&lt;/p&gt;
&lt;p&gt;The log files may contain sensitive information, so be careful with them, and
they also grow indefinitely. The proxy does not currently implement any log
rotation or redaction.&lt;/p&gt;
&lt;p&gt;The code is on GitHub: &lt;a href="https://github.com/kortsi/cc-gh-proxy"&gt;kortsi/cc-gh-proxy&lt;/a&gt;.&lt;/p&gt;</content><category term="Tech"></category><category term="Claude"></category><category term="GitHub"></category><category term="Copilot"></category><category term="Python"></category></entry><entry><title>Moving from WordPress to Pelican</title><link href="https://mikko.kortelainen.io/blog/moving-from-wordpress-to-pelican/" rel="alternate"></link><published>2026-03-17T12:00:00+02:00</published><updated>2026-03-17T12:00:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2026-03-17:/blog/moving-from-wordpress-to-pelican/</id><summary type="html">&lt;p&gt;After running this blog on WordPress since 2007, I've finally moved it to a
static site. The trigger was my old hosting provider shutting down their data
center at the end of March 2026. My server was getting old, too.&lt;/p&gt;
&lt;p&gt;Rather than migrating WordPress somewhere else, I decided to go …&lt;/p&gt;</summary><content type="html">&lt;p&gt;After running this blog on WordPress since 2007, I've finally moved it to a
static site. The trigger was my old hosting provider shutting down their data
center at the end of March 2026. My server was getting old, too.&lt;/p&gt;
&lt;p&gt;Rather than migrating WordPress somewhere else, I decided to go static. I also
got a new domain (mikko.kortelainen.io) and a fresh coat of paint for the blog.&lt;/p&gt;
&lt;p&gt;I have been lazy about writing new content for years, but I still wanted to keep
the old articles and comments alive. The new stack is more maintainable and
cost-effective, and I hope it will encourage me to write more often.&lt;/p&gt;
&lt;div class="section" id="the-new-stack"&gt;
&lt;h2&gt;The New Stack&lt;/h2&gt;
&lt;p&gt;The blog now runs on &lt;a class="reference external" href="https://getpelican.com/"&gt;Pelican&lt;/a&gt;, a Python-based static
site generator. The infrastructure is on AWS, managed with CDK:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;S3&lt;/strong&gt; for static file hosting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CloudFront&lt;/strong&gt; for CDN and HTTPS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Lambda + API Gateway&lt;/strong&gt; for the comment system&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;DynamoDB&lt;/strong&gt; for storing comments and ratings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Articles and comments from 2007-2023 were migrated from WordPress, and the old domain redirects to the new one.&lt;/p&gt;
&lt;p&gt;I wanted to keep everything that mattered from the old site:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;All articles and their content&lt;/li&gt;
&lt;li&gt;All comments with full threading&lt;/li&gt;
&lt;li&gt;Article ratings migrated from the WordPress Post Ratings plugin&lt;/li&gt;
&lt;li&gt;Old domain URLs redirect to the new domain, including the date-based
WordPress URL scheme (&lt;tt class="docutils literal"&gt;/blog/2015/03/20/slug/&lt;/tt&gt; becomes &lt;tt class="docutils literal"&gt;/blog/slug/&lt;/tt&gt;)&lt;/li&gt;
&lt;li&gt;RSS feed subscribers are redirected to the new Atom feed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some articles were missing content for an unknown reason, and I was not able to
recover everything.&lt;/p&gt;
&lt;p&gt;The comment system is custom-built: a Lambda function behind API Gateway with
Akismet spam filtering, per-IP rate limiting, and optional Google sign-in.&lt;/p&gt;
&lt;p&gt;The new design is minimalist and mobile-friendly, with a light/dark mode toggle.&lt;/p&gt;
&lt;p&gt;Let me know if you find any issues with the new site or have suggestions for improvements.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Pelican"></category><category term="AWS"></category><category term="WordPress"></category></entry><entry><title>Enabling Quectel EM05-G Modem on Linux</title><link href="https://mikko.kortelainen.io/blog/enabling-quectel-em05-g-modem-on-linux/" rel="alternate"></link><published>2022-12-21T22:55:00+02:00</published><updated>2022-12-21T22:55:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2022-12-21:/blog/enabling-quectel-em05-g-modem-on-linux/</id><summary type="html">&lt;p&gt;My new Thinkpad has a Quectel EM05-G modem. For some reason it refused to
connect, even though it showed up in Gnome settings on Ubuntu 22.10. I checked
with &lt;code class="sh"&gt;mmcli&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;/code&gt; and it said &lt;code class="sh"&gt;sim&lt;span class="w"&gt; &lt;/span&gt;missing&lt;/code&gt; as its state.&lt;/p&gt;
&lt;p&gt;After some Googling it appeared the modem ships in …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My new Thinkpad has a Quectel EM05-G modem. For some reason it refused to
connect, even though it showed up in Gnome settings on Ubuntu 22.10. I checked
with &lt;code class="sh"&gt;mmcli&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;/code&gt; and it said &lt;code class="sh"&gt;sim&lt;span class="w"&gt; &lt;/span&gt;missing&lt;/code&gt; as its state.&lt;/p&gt;
&lt;p&gt;After some Googling it appeared the modem ships in some kind of a locked state,
so it only works in Windows. I checked with &amp;quot;mbimcli&amp;quot;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;libmbim-utils&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mbimcli&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;/dev/cdc-wdm0&lt;span class="w"&gt; &lt;/span&gt;--quectel-query-radio-state&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;/dev/cdc-wdm0&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Radio&lt;span class="w"&gt; &lt;/span&gt;state&lt;span class="w"&gt; &lt;/span&gt;retrieved:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'fcc-locked'&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It was easy to unlock:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mbimcli&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;/dev/cdc-wdm0&lt;span class="w"&gt; &lt;/span&gt;--quectel-set-radio-state&lt;span class="o"&gt;=&lt;/span&gt;on&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;/dev/cdc-wdm0&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Successfully&lt;span class="w"&gt; &lt;/span&gt;requested&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;radio&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mbimcli&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;/dev/cdc-wdm0&lt;span class="w"&gt; &lt;/span&gt;--quectel-query-radio-state&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;/dev/cdc-wdm0&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Radio&lt;span class="w"&gt; &lt;/span&gt;state&lt;span class="w"&gt; &lt;/span&gt;retrieved:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'on'&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;After this, Gnome was able to enable the mobile broadband connection without
problem.&lt;/p&gt;
</content><category term="Blog"></category><category term="ThinkPad"></category></entry><entry><title>Tunneling SSH over HTTPS with stunnel</title><link href="https://mikko.kortelainen.io/blog/tunneling-ssh-over-https-with-stunnel/" rel="alternate"></link><published>2020-02-06T15:56:00+02:00</published><updated>2020-02-06T15:56:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2020-02-06:/blog/tunneling-ssh-over-https-with-stunnel/</id><summary type="html">&lt;p&gt;I was faced with a firewall denying access to the outside world using ssh. All I
had was http/https access via a proxy server which required authentication. I
had an Ubuntu jump host outside the network connected to the internet with a
free 443 port. I tried accessing that …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I was faced with a firewall denying access to the outside world using ssh. All I
had was http/https access via a proxy server which required authentication. I
had an Ubuntu jump host outside the network connected to the internet with a
free 443 port. I tried accessing that with
&lt;a class="reference external" href="https://tools.kali.org/maintaining-access/httptunnel"&gt;httptunnel&lt;/a&gt;
and
&lt;a class="reference external" href="https://github.com/proxytunnel/proxytunnel"&gt;proxytunnel&lt;/a&gt;,
but could get neither to work with this proxy server.&lt;/p&gt;
&lt;p&gt;The solution that worked in this particular case was
&lt;a class="reference external" href="https://www.stunnel.org/"&gt;stunnel&lt;/a&gt;.
It can wrap any TCP connection into an https
session which was not rejected by the proxy server I was facing.&lt;/p&gt;
&lt;div class="section" id="client"&gt;
&lt;h2&gt;Client&lt;/h2&gt;
&lt;p&gt;Install stunnel on laptop (mine is Ubuntu 18.04), and use openssl to generate a
key and a certificate:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt;
&lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;stunnel4&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/stunnel&lt;span class="w"&gt;
&lt;/span&gt;openssl&lt;span class="w"&gt; &lt;/span&gt;genrsa&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;stunnel.key&lt;span class="w"&gt;
&lt;/span&gt;openssl&lt;span class="w"&gt; &lt;/span&gt;req&lt;span class="w"&gt; &lt;/span&gt;-new&lt;span class="w"&gt; &lt;/span&gt;-key&lt;span class="w"&gt; &lt;/span&gt;stunnel.key&lt;span class="w"&gt; &lt;/span&gt;-x509&lt;span class="w"&gt; &lt;/span&gt;-days&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-out&lt;span class="w"&gt; &lt;/span&gt;stunnel.crt&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# (you can accept openssl defaults)
&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;stunnel.crt&lt;span class="w"&gt; &lt;/span&gt;stunnel.key&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;stunnel.pem
&lt;/pre&gt;
&lt;p&gt;The values you enter in the client certificate request do not matter.&lt;/p&gt;
&lt;p&gt;Next, create stunnel configuration. You should replace the variables with your
own values.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;PROXY_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;your proxy_address:proxy_port&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;PROXY_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;your proxy username&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;PROXY_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;your proxy password&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;JUMP_HOST_ADDRESS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;your jump host address&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;/etc/stunnel/stunnel.conf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;EOF
pid=/var/run/stunnel.pid
cert=/etc/stunnel/stunnel.pem

[ssh]
client=yes
libwrap=no
accept=2222
connect=$PROXY_ADDRESS
protocolUsername=$PROXY_USERNAME
protocolPassword=$PROXY_PASSWORD
protocolHost=$JUMP_HOST_ADDRESS:443
EOF&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;stunnel4
&lt;/pre&gt;
&lt;p&gt;Stunnel should now be running on your laptop. It will forward any connection you
make to &lt;strong&gt;localhost:2222&lt;/strong&gt; to your $JUMP_HOST port &lt;strong&gt;443&lt;/strong&gt; and wrap it in an
https request.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="jump-host"&gt;
&lt;h2&gt;Jump host&lt;/h2&gt;
&lt;p&gt;The proxy server did not accept self-signed certificates, so I installed
&lt;a class="reference external" href="https://certbot.eff.org/"&gt;certbot&lt;/a&gt; to get a working certificate on the jump
host (mine is Ubuntu 19.10):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt;
&lt;/span&gt;add-apt-repository&lt;span class="w"&gt; &lt;/span&gt;ppa:certbot/certbot&lt;span class="w"&gt;
&lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;certbot&lt;span class="w"&gt;
&lt;/span&gt;certbot&lt;span class="w"&gt; &lt;/span&gt;certonly&lt;span class="w"&gt; &lt;/span&gt;--standalone&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Make note where certbot installs the private key
# and the full certificate chain&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Install stunnel on server and configure it:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;JUMP_HOST_DNS_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;lt;your jump host DNS name&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;stunnel4&lt;span class="w"&gt;

&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;/etc/stunnel/stunnel.conf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;EOF
pid=/var/run/stunnel.pid
key=/etc/letsencrypt/live/$JUMP_HOST_DNS_NAME/privkey.pem
cert=/etc/letsencrypt/live/$JUMP_HOST_DNS_NAME/fullchain.pem

[ssh]
accept=443
connect=127.0.0.1:22
EOF&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;stunnel4
&lt;/pre&gt;
&lt;p&gt;Make sure the &lt;strong&gt;key&lt;/strong&gt; and &lt;strong&gt;cert&lt;/strong&gt; paths are pointing to correct certbot files.&lt;/p&gt;
&lt;p&gt;Stunnel should now be running on the jump host as well. It will listen on port
&lt;strong&gt;443&lt;/strong&gt;, unwrap the https and redirect the connection to localhost port &lt;strong&gt;22&lt;/strong&gt;,
where sshd should be listening.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="test-from-client"&gt;
&lt;h2&gt;Test From Client&lt;/h2&gt;
&lt;p&gt;Now you should be able to ssh to your jump host by connecting to the local stunnel instance:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
ssh&lt;span class="w"&gt; &lt;/span&gt;localhost&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2222&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="OpenSSH"></category></entry><entry><title>Methods for Both Classes and Instances in Python</title><link href="https://mikko.kortelainen.io/blog/methods-for-both-classes-and-instances-in-python/" rel="alternate"></link><published>2017-07-24T12:28:00+03:00</published><updated>2017-07-24T12:28:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2017-07-24:/blog/methods-for-both-classes-and-instances-in-python/</id><summary type="html">&lt;p&gt;I came across a situation where it would be nice for a Python class to have a method which works for both the class and its instances, and when called in an instance context, to know on which instance it was invoked. Python does not support this directly, but as …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I came across a situation where it would be nice for a Python class to have a method which works for both the class and its instances, and when called in an instance context, to know on which instance it was invoked. Python does not support this directly, but as it is a very flexible language, it can be done. To make it work somewhat nicely requires just a few lines of not so obvious code.&lt;/p&gt;
&lt;p&gt;To have Python call a method in the context of a class requires the use of the decorator &lt;tt class="docutils literal"&gt;&amp;#64;classmethod&lt;/tt&gt;. You can call such a method for an instance as well, but the method is only passed the class as an argument, not the instance.&lt;/p&gt;
&lt;p&gt;Here's a an example:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;X&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'cls:    &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'self:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'NO SELF!'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'args:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'kwargs: &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The class has one classmethod which simply prints what it knows about the world around it. It knows the class and the arguments passed to it. When invoked on a class instance, it does not know which instance it was invoked on.&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwarg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;NO&lt;/span&gt; &lt;span class="n"&gt;SELF&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwarg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="n"&gt;NO&lt;/span&gt; &lt;span class="n"&gt;SELF&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;What I needed was to have &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; defined when invoked in an instance context. I solved it by injecting self into the classmethod when the class constructor is run at instantiation time. This requires a slight modification to the classmethod's signature, and replacing the original classmethod with an instancemethod which takes both the class as a positional argument and the instance as a keyword argument. This is achieved nicely with a utility function called &lt;tt class="docutils literal"&gt;class2instancemethod&lt;/tt&gt;:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MethodType&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;class2instancemethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Converts a classmethod into an instancemethod&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;class2instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Remove first positional arg which is self&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# and move it to kwargs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]),&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MethodType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class2instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;X&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;class2instancemethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'cls:    &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'self:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'args:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'kwargs: &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;There are four things to note here. The first one is the &lt;tt class="docutils literal"&gt;class2instancemethod&lt;/tt&gt; utility function which takes a classmethod and a class instance as argument and returns an instancemethod which has class (&amp;quot;cls&amp;quot;) as the first positional parameter and instance (&amp;quot;self&amp;quot;) as a keyword argument.&lt;/p&gt;
&lt;p&gt;The second interesting thing is the class constructor which calls our utility function at class instantiation time and replaces the original classmethod with our patched version.&lt;/p&gt;
&lt;p&gt;The third interesting thing is the signature of the classmethod m:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Argument list now contains self as a keyword argument. When invoked in a class context, &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; will be &lt;tt class="docutils literal"&gt;None&lt;/tt&gt;. When invoked in an instance context, &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; will receive the instance.&lt;/p&gt;
&lt;p&gt;The fourth thing to note is the print line:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
print('self:   {}'.format(self))
&lt;/pre&gt;
&lt;p&gt;We now have a &lt;tt class="docutils literal"&gt;self&lt;/tt&gt; to print. Here's what looks like now:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwarg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwarg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x7f1fe54250b8&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;So now it is possible to have the classmethod know the instance when called in an instance context.&lt;/p&gt;
&lt;p&gt;With this implementation we would have to patch every method in our constructor method, which is repetitive and error-prone.&lt;/p&gt;
&lt;p&gt;We can improve the situation by making our own decorator for such methods, and a helper function which needs to be called just once in the constructor. Here's the full code:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;types&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MethodType&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;class2instancemethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Converts a classmethod into an instancemethod&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;class2instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Remove first positional arg which is self&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# and move it to kwargs&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]),&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;MethodType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class2instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;_c2im_attr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'_convert_to_instancemethod'&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;instancemethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Decorator for classmethods which should be
    converted to instancemethods in constructor.
    You must run make_instancemethods(self) in your
    constructor to actually make it happen.

    Eg:

    class X:
        &amp;#64;classmethod
        &amp;#64;instancemethod
        def m1(cls, *args, self=None, **kwargs):
            # - cls is always set
            # - self is set when invoked on an instance
            # - args &amp;amp; kwargs stay the same for both ways

            print('cls:    {}'.format(cls))
            print('self:   {}'.format(self))
            print('args:   {}'.format(args))
            print('kwargs: {}'.format(kwargs))

            if self is not None:
                print('Called on instance {}'.format(self))
            else:
                print('Called on class {}'.format(cls))

        &amp;#64;instancemethod
        &amp;#64;classmethod
        def m2(cls, *args, self=None, **kwargs):
            print('self:   {}'.format(self))

        def __init__(self):
            # Changes all classmethods marked with
            # &amp;#64;instancemethod so that self is injected
            # as kwarg
            self.make_instancemethods(self)
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="nb"&gt;classmethod&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Set flag&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_c2im_attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Dig out the original method and set flag there&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="vm"&gt;__func__&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_c2im_attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_instancemethods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Takes all classmethods decorated with the
    &amp;#64;instancemethod decorator and injects self
    as a kwarg.&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;c2im&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'__'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;c2im&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_c2im_attr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                    &lt;span class="n"&gt;class2instancemethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And here's an example on how to use it:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;X&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;make_instancemethods&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;instancemethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'cls:    &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'self:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'args:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'kwargs: &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;instancemethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;m2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'self:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg1:   &lt;/span&gt;&lt;span class="si"&gt;{}&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Example output:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwarg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;kwarg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="nc"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="s1"&gt;'&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x7fcf7c9c5550&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'arg'&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'kwarg'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x7fcf7c9c5550&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;__main__&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="nb"&gt;object&lt;/span&gt; &lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="mh"&gt;0x7fcf7c9c5550&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;arg1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;   &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This makes it quite easy to have classmethods which are able to get the target object when invoked on an instance.&lt;/p&gt;
&lt;p&gt;The only tricky thing is to have the arguments in the right order. The order should be this:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;cls&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;any positional arguments&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;*args&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;any named keyword arguments you wish to be able to use also as positional ones (when not using *args)&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;self=None&lt;/tt&gt;&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;*kwargs&lt;/tt&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Only &lt;tt class="docutils literal"&gt;cls&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;self=None&lt;/tt&gt; are required, the rest are optional.&lt;/p&gt;
&lt;p&gt;As a final note I would like to point out that this has only been tested with Python 3.5.&lt;/p&gt;
</content><category term="Blog"></category><category term="Python"></category></entry><entry><title>Enable vi editing mode in IPython 5</title><link href="https://mikko.kortelainen.io/blog/enable-vi-editing-mode-in-ipython-5/" rel="alternate"></link><published>2016-08-04T12:46:00+03:00</published><updated>2016-08-04T12:46:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2016-08-04:/blog/enable-vi-editing-mode-in-ipython-5/</id><content type="html">&lt;p&gt;Create default profile and set editing mode to 'vi':&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ipython profile create
echo &amp;quot;c.TerminalInteractiveShell.editing_mode = 'vi'&amp;quot; \
  &amp;gt;&amp;gt;~/.ipython/profile_default/ipython_config.py
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Python"></category><category term="IPython"></category></entry><entry><title>Keeping SSH Tunnels Up With Autossh</title><link href="https://mikko.kortelainen.io/blog/keeping-ssh-tunnels-up-with-autossh/" rel="alternate"></link><published>2015-11-27T17:05:00+02:00</published><updated>2015-11-27T17:05:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2015-11-27:/blog/keeping-ssh-tunnels-up-with-autossh/</id><summary type="html">&lt;p&gt;To keep an ssh connection with a tunnel for port forwarding &amp;nbsp;up reliably we can use the &lt;a class="reference external" href="http://www.harding.motd.ca/autossh/"&gt;autossh&lt;/a&gt; command by Carson Harding.&amp;nbsp;If the connection drops, autossh will restart it. Here's&amp;nbsp;a quick recipe to forward local port 33306 to a remote MySQL host listening on port 3306:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="c1"&gt;# Install autossh …&lt;/span&gt;&lt;/pre&gt;</summary><content type="html">&lt;p&gt;To keep an ssh connection with a tunnel for port forwarding &amp;nbsp;up reliably we can use the &lt;a class="reference external" href="http://www.harding.motd.ca/autossh/"&gt;autossh&lt;/a&gt; command by Carson Harding.&amp;nbsp;If the connection drops, autossh will restart it. Here's&amp;nbsp;a quick recipe to forward local port 33306 to a remote MySQL host listening on port 3306:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="c1"&gt;# Install autossh
&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;autossh&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Make a user and su to it
&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;useradd&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/false&lt;span class="w"&gt; &lt;/span&gt;autossh&lt;span class="w"&gt;
&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;autossh&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/bash&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Our connection parameters
&lt;/span&gt;&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sshuser&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DESTINATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;192.168.1.1&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;FORWARD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;33306:127.0.0.1:3306&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Make an ssh identity, copy to remote
&lt;/span&gt;ssh-keygen&lt;span class="w"&gt;
&lt;/span&gt;ssh-copy-id&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;&amp;#64;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Set keepalive options
&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;~/.ssh/config&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;'EOF'
ServerAliveInterval 30
ServerAliveCountMax 5
EOF&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# To start foreground:
&lt;/span&gt;autossh&lt;span class="w"&gt; &lt;/span&gt;-M&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-L&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FORWARD&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# To start background:
&lt;/span&gt;autossh&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;-M&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-N&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;BatchMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-L&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FORWARD&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# To stop:
&lt;/span&gt;killall&lt;span class="w"&gt; &lt;/span&gt;autossh&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Leave su
&lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Start background as autossh
&lt;/span&gt;&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sshuser&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DESTINATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;192.168.1.1&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;FORWARD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;33306:127.0.0.1:3306&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;autossh&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/bash&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;autossh -f -M 0 -N -o BatchMode=yes &lt;/span&gt;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;&lt;span class="s2"&gt; -l &lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;&lt;span class="s2"&gt; -L &lt;/span&gt;&lt;span class="nv"&gt;$FORWARD&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;We create a local user which will be used to run the autossh command. We also create a new ssh key pair and copy the public key to the remote user account on the destination host. The ServerAlive options will make ssh test the connection periodically, in this case every 30 seconds. If 5 consecutive tests fail, ssh will terminate. Autossh will then restart the connection.&lt;/p&gt;
&lt;p&gt;Autossh itself can be run in the foreground, when it will behave like a regular ssh session, or in the background, which is especially useful for keeping up ssh tunnels for port forwarding. The -f option will make autossh run in the background. The -M 0 option disables&amp;nbsp;the monitoring channel which we do not need since ssh will exit when it detects a dropped connection. The -N option of ssh causes ssh not to run any command, not even a shell in the session. It just starts your tunnels, which is what we need. The -o BatchMode option will disable password authentication.&lt;/p&gt;
&lt;p&gt;To autostart at reboot, add these lines to /etc/rc.local:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sshuser&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DESTINATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;192.168.1.1&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;FORWARD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;33306:127.0.0.1:3306&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;autossh&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/bash&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;autossh -f -M 0 -N -o BatchMode=yes &lt;/span&gt;&lt;span class="nv"&gt;$DESTINATION&lt;/span&gt;&lt;span class="s2"&gt; -l &lt;/span&gt;&lt;span class="nv"&gt;$USERNAME&lt;/span&gt;&lt;span class="s2"&gt; -L &lt;/span&gt;&lt;span class="nv"&gt;$FORWARD&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Remember to add it before the exit line if there is one.&lt;/p&gt;
&lt;p&gt;This thing has been tested on Ubuntu 14.04.&lt;/p&gt;
</content><category term="Blog"></category><category term="OpenSSH"></category></entry><entry><title>Flask-SQLAlchemy and PostgreSQL Unit Testing with Transaction Savepoints</title><link href="https://mikko.kortelainen.io/blog/flask-sqlalchemy-and-postgresql-unit-testing-with-transaction-savepoints/" rel="alternate"></link><published>2015-10-22T23:04:00+03:00</published><updated>2015-10-22T23:04:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2015-10-22:/blog/flask-sqlalchemy-and-postgresql-unit-testing-with-transaction-savepoints/</id><summary type="html">&lt;p&gt;PostgreSQL provides us two very powerful features which are helpful with unit testing: transactional DDL and transaction savepoints. In this article I will show you how to use those with Flask-SQLAlchemy unit tests.&lt;/p&gt;
&lt;p&gt;Transactional DDL means you can create tables inside a transaction, run tests against them, and roll back …&lt;/p&gt;</summary><content type="html">&lt;p&gt;PostgreSQL provides us two very powerful features which are helpful with unit testing: transactional DDL and transaction savepoints. In this article I will show you how to use those with Flask-SQLAlchemy unit tests.&lt;/p&gt;
&lt;p&gt;Transactional DDL means you can create tables inside a transaction, run tests against them, and roll back your changes after you are done. The database will be left in the same state as it was when you started. If you started with an empty database, nothing will be left in the database afterwards.&lt;/p&gt;
&lt;p&gt;Savepoints allow you to roll back a part of a transaction without affecting what has happened before that savepoint was created. You can run a single test inside a savepoint and roll back just the changes that single test made without affecting the changes your set-up code has done before the savepoint.&lt;/p&gt;
&lt;p&gt;That means you can create a large number of tables and other database objects in the beginning of your test suite and then run individual tests inside nested transaction using savepoints. There is no need to drop and re-create the whole database schema for each test.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="auto-toc simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#postgresql-database-for-unit-tests" id="toc-entry-1"&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;PostgreSQL Database for Unit Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#other-requirements" id="toc-entry-2"&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Other Requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#an-app-a-model-and-some-tests" id="toc-entry-3"&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;An App, a Model, and Some Tests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#tests-in-nested-transactions" id="toc-entry-4"&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Tests in Nested Transactions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#transactional-ddl" id="toc-entry-5"&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Transactional DDL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#abstract-it-out" id="toc-entry-6"&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;Abstract it Out&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#download-the-code" id="toc-entry-7"&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Download the Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="postgresql-database-for-unit-tests"&gt;
&lt;h2&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;PostgreSQL Database for Unit Tests&lt;/h2&gt;
&lt;p&gt;We will need an empty database to run our unit tests against. If you have PostgreSQL already installed, at least on Ubuntu there are command line tools to get it done:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
postgres&amp;#64;host:~$&lt;span class="w"&gt; &lt;/span&gt;createuser&lt;span class="w"&gt; &lt;/span&gt;-P&lt;span class="w"&gt; &lt;/span&gt;unittestuser&lt;span class="w"&gt;
&lt;/span&gt;Enter&lt;span class="w"&gt; &lt;/span&gt;password&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;new&lt;span class="w"&gt; &lt;/span&gt;role:&lt;span class="w"&gt; &lt;/span&gt;password&lt;span class="w"&gt;
&lt;/span&gt;Enter&lt;span class="w"&gt; &lt;/span&gt;it&lt;span class="w"&gt; &lt;/span&gt;again:&lt;span class="w"&gt; &lt;/span&gt;password&lt;span class="w"&gt;

&lt;/span&gt;postgres&amp;#64;host:~$&lt;span class="w"&gt; &lt;/span&gt;createdb&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;unittestuser&lt;span class="w"&gt; &lt;/span&gt;unittestdb
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;createuser&lt;/em&gt; command creates a database user. The &lt;em&gt;createdb&lt;/em&gt; creates the database, and the -O option sets the owner of the database.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="other-requirements"&gt;
&lt;h2&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Other Requirements&lt;/h2&gt;
&lt;p&gt;You obviously need to install Flask-SQLAlchemy and psycopg2 for PostgreSQL connectivity:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="o"&gt;(&lt;/span&gt;virtualenv&lt;span class="o"&gt;)&lt;/span&gt;user&amp;#64;host:~$&lt;span class="w"&gt; &lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;flask&lt;span class="w"&gt; &lt;/span&gt;flask-sqlalchemy&lt;span class="w"&gt; &lt;/span&gt;psycopg2
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="an-app-a-model-and-some-tests"&gt;
&lt;h2&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;An App, a Model, and Some Tests&lt;/h2&gt;
&lt;p&gt;First let's take a look at an ordinary test suite. Flask-SQLAlchemy wraps SQLAlchemy and integrates it with Flask, providing some additional functionality with it. A very minimal Flask app with Flask-SQLAlchemy and PostgreSQL support could look something like below.&lt;/p&gt;
&lt;p&gt;Please note that I haven't tested the following example nor have I run its tests. The downloadable file at the end of this article contains a working and tested example, and includes the tests used to test it. The example below gives us something we can start do discuss here. Let me know if you find errors.&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask.ext.sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'SQLALCHEMY_DATABASE_URI'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'postgresql+psycopg2://unittestuser:password&amp;#64;localhost/unittestdb'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_name&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Our app is in deed very minimal. It doesn't even have any views. But it is enough for our purposes.&lt;/p&gt;
&lt;p&gt;A minimal test suite for our database model might look like this:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model modification should modify model&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'New name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s1"&gt;'New name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Note that the &lt;em&gt;db.create_all/drop_all&lt;/em&gt; is executed for each test, as well as the initial model adding. We can avoid this by using a transaction and some savepoints.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tests-in-nested-transactions"&gt;
&lt;h2&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Tests in Nested Transactions&lt;/h2&gt;
&lt;p&gt;So how do we use savepoints to our advantage when writing unit tests for Flask-SQLAlchemy apps? To test arbitrary Flask-SQLAlchemy code inside a nested transaction, we must replace the global &lt;em&gt;db.session&lt;/em&gt; object with one that runs in a nested transaction. After all, your code is likely to perform all of its database operations through the &lt;em&gt;db.session&lt;/em&gt; object.&lt;/p&gt;
&lt;p&gt;We can choose to use either the &lt;em&gt;TestCase&lt;/em&gt; class's &lt;em&gt;setUpClass/tearDownClass&lt;/em&gt; classmethods which are called once per each &lt;em&gt;TestCase&lt;/em&gt;, or the &lt;em&gt;setUpModule/tearDownModule&lt;/em&gt; functions which unittest will call once per module when running the tests. And we can even use both if we want to do some setup work at the module level and some more in each class.&lt;/p&gt;
&lt;p&gt;Here's an example of how to do it using the classmethods:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Create schema&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDownClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Drop schema&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop_all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Create two savepoint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Make backup of session and replace with savepoint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Roll back to first savepoint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Restore original session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_models_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Models should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model modification should modify model&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'New name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="s1"&gt;'New name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;setUpClass&lt;/em&gt; method is only run once in the beginning of the test. The database schema is created there. The schema is dropped in the end in the &lt;em&gt;tearDownClass&lt;/em&gt; method.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;setUp&lt;/em&gt; method now creates two savepoints. Strictly speaking only one savepoint is needed, but I would recommend two because the code you are testing might call &lt;em&gt;db.session.commit()&lt;/em&gt; and that will commit the savepoint it is running in. A committed savepoint can not be rolled back to. So in the &lt;em&gt;tearDown&lt;/em&gt; method we will roll back to the first savepoint which will be available also in the case the tested code commits. When the savepoint is rolled back, the next test case will see the database exactly like it was after the &lt;em&gt;setUpClass&lt;/em&gt; call.&lt;/p&gt;
&lt;p&gt;Note that if your code does multiple commits per test, this doesn't work and you will receive exceptions from SQLAlchemy. You can add more savepoints to work around that. You must have one more savepoint than you have commits in a single test. On the other hand, it is a good way of finding code paths that perform multiple commits. Doing lots of commits will result in a lot of disk activity and will slow down your application.&lt;/p&gt;
&lt;p&gt;If you want to do multiple commits in your test case, you can use &lt;em&gt;db.session.begin_nested&lt;/em&gt; and commit that:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_with_commits&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;savepoint1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;do&lt;/span&gt; &lt;span class="n"&gt;stuff&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;savepoint1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stuff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;savepoint1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;savepoint2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="n"&gt;do&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="n"&gt;stuff&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;savepoint2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stuff&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;savepoint2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="o"&gt;...&lt;/span&gt; &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;some&lt;/span&gt; &lt;span class="n"&gt;more&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Stuff you do inside a committed savepoint will be available later on, so the &lt;em&gt;savepoint1&lt;/em&gt; stuff in the example above will be available inside &lt;em&gt;savepoint2&lt;/em&gt;, unless you choose to roll back to &lt;em&gt;savepoint1&lt;/em&gt; instead of committing. Eventually of course the test &lt;em&gt;tearDown&lt;/em&gt; will roll back to its own savepoint to undo everything you did before running the next test.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="transactional-ddl"&gt;
&lt;h2&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Transactional DDL&lt;/h2&gt;
&lt;p&gt;The next logical step is to run &lt;em&gt;db.create_all()&lt;/em&gt; inside the same transaction as the tests. This way the database you run unit tests against will start empty and end up empty without even the need to drop tables afterwards.&lt;/p&gt;
&lt;p&gt;In fact it might even be possible to run it against a database which has existing tables already if you drop first, and keep your old data after the tests. But I haven't tested if it works or not. It is probably not a good idea, though. There might be side effects since some database objects, such as sequences, are not kept completely isolated inside the transaction.&lt;/p&gt;
&lt;p&gt;Flask-SQLAlchemy does not allow us to run the metadata creation inside the same transaction as the rest of the app. Again we need to monkey patch the db object and replace the session with our own, this time to make a new database connection. Flask-SQAlchemy depends on the &lt;em&gt;db.session&lt;/em&gt; object to be a factory for new sessions, but we want to avoid new sessions since we want everything to run inside a single transaction. We will have to use a custom session which is a &amp;quot;factory&amp;quot; that returns itself.&lt;/p&gt;
&lt;p&gt;Below is an example of how to do it in the &lt;em&gt;setUpModule/tearDownModule&lt;/em&gt; functions.&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask.ext.sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestingSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autocommit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autoflush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Flask-SQLAlchemy wants to create a new session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Simply return the existing session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# mapper is None if someone tries to just get a connection&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapped_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'info'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;bind_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bind_key'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bind_key&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqlalchemy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bind_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpModule&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;# Create a connection and start a transaction. This is needed so that&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# we can run the drop_all/create_all inside the same transaction as&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# the tests&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;# Back up the original session and replace with our own&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;session_backup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TestingSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;## Drop all to get an empty database free of old crud just in case&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;## Create everything&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDownModule&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# Roll back everything&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;# Restore backup&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyModelTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Create a model instance for this class&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'Test'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Create class savepoint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Backup and replace&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDownClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Roll back to class savepoint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Restore original session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Create two test savepoints&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Make backup of session and replace with savepoint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# This is for using app_context().pop()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Roll back to first test savepoint&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Restore original session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="o"&gt;.&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;What &lt;em&gt;setUpModule&lt;/em&gt; does is it makes its own database connection instead of using the one Flask-SQLAlchemy has created. This is needed so that we can begin a transaction, run the DDL in it, and continue with running the tests in the same transaction. The Flask-SQLAlchemy &lt;em&gt;db.create_all()&lt;/em&gt; will commit the schema into the database if we use it directly. The &lt;em&gt;TestingSession&lt;/em&gt; is a modified Flask-SQLAlchemy &lt;em&gt;SignallingSessionclass&lt;/em&gt;. It keeps everything running in our single transaction.&lt;/p&gt;
&lt;p&gt;Another detail to note is the &lt;em&gt;db.session.remove = lambda: None&lt;/em&gt; statement in the test &lt;em&gt;setUp&lt;/em&gt; code. It is a required fix when you push the application context in your own &lt;em&gt;setUp&lt;/em&gt; method and pop it in the &lt;em&gt;tearDown&lt;/em&gt; method. Flask-SQLAlchemy will raise an exception during app context teardown without it.&lt;/p&gt;
&lt;p&gt;The rest of it is a simple extension of the original idea. Here we have two levels of setup code instead of one, and savepoints to guard them both. The &lt;em&gt;setUpModule&lt;/em&gt; call creates the schema once for the whole module, while the model creation is done in the &lt;em&gt;setUpClass&lt;/em&gt; method. It means that if you add another &lt;em&gt;TestCase&lt;/em&gt; in the same module the schema will stay intact but the model inserted or any other operation performed in &lt;em&gt;MyModelTestCase's&lt;/em&gt; &lt;em&gt;setUpClass&lt;/em&gt; will only be there for &lt;em&gt;MyModelTestCase's&lt;/em&gt; tests.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="abstract-it-out"&gt;
&lt;h2&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;Abstract it Out&lt;/h2&gt;
&lt;p&gt;It is obviously not a good idea to keep code like that in each test module so let's extract the functionality and put it in a separate module which we will call &lt;em&gt;flask_sqlalchemy_testing.&lt;/em&gt; The code for this and the tests can be downloaded at the end of the article.&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask.ext.sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestingSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_app&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autocommit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;autoflush&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__call__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Flask-SQLAlchemy wants to create a new session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Simply return the existing session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# mapper is None if someone tries to just get a connection&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mapped_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'info'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;bind_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bind_key'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;bind_key&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;flask&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ext&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqlalchemy&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_state&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;bind_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;SessionBase&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mapper&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;clause&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;unittest&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpModule&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Sets up the module so that we can run the whole test suite inside
    a single transaction. Each test will be executed in a nested transaction
    using PostgreSQL savepoints.

    We will:

    1. Start a transaction
    2. Drop everything
    3. (Re-)create everything
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;# Create a connection and start a transaction. This is needed so that&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# we can run the drop_all/create_all inside the same transaction as&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# the tests&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;connection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;transaction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;# Back up the original session and replace with our own&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;session_backup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TestingSession&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;## Drop all to get an empty database free of old crud&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;drop_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;## Create everything&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create_all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDownModule&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Roll back everything, leaving database as it was before we started&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;connection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;# Restore backup&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FlaskDbTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Makes a savepoint for this class&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Replace app db object temporarily with a nested tx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDownClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Rolls back to the class savepoint&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Restore original session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Makes a savepoint for this test&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# We actually need to make 2 savepoints in case the code to be tested&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# happens to issue a commit so that we can roll back to this point.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# A commit in the tested code can only commit &amp;quot;savepoint2&amp;quot; so we&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# will use &amp;quot;savepoint&amp;quot; for the rollback.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Replace app db object temporarily with a nested tx&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# This is for using app_context().pop()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Rolls back to the test class savepoint&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# Roll back savepoint - schema will back to fresh&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;savepoint1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rollback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Restore original session&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session_backup&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Let's use an app which has two models for a change:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask.ext.sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Flask&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'SQLALCHEMY_DATABASE_URI'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'postgresql+psycopg2://unittestuser:password&amp;#64;localhost/unittestdb'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SQLAlchemy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here's the test module:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;flask_sqlalchemy_testing&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask_sqlalchemy_testing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FlaskDbTestCase&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;app&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpModule&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;flask_sqlalchemy_testing&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUpModule&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="c1"&gt;# You can issue module-wide setup operations here&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;# (these will be rolled back after all tests in this module have run)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;flask_sqlalchemy_testing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tearDownModule&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelXTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlaskDbTestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelXTestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# These will be rolled back after all the tests in this class&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelXTestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# These will be rolled back after each test&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_x_instance_0_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model X instance 0 should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_x_instance_1_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model X instance 1 should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_x_instance_2_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model X instance 2 should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_y_instance_0_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model Y instance 0 should exist also in ModelXTestCase&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_y_instance_1_exists_not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model Y instance 1 should not exist in ModelXTestCase&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_y_instance_2_exists_not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model Y instance 2 should not exist in ModelXTestCase&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_savepoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Test model states with savepoint&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;modelx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;model_state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;savepoint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;begin_nested&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;savepoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modelx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pending&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;savepoint&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;persistent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ModelYTestCase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;FlaskDbTestCase&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="nd"&gt;&amp;#64;classmethod&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelYTestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUpClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelYTestCase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flush&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_y_instance_0_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model Y instance 0 should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_y_instance_1_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model Y instance 1 should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_y_instance_2_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model Y instance 2 should exist&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelY&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_x_instance_0_exists&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model X instance 0 should exist also in ModelYTestCase&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNotNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_x_instance_1_exists_not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model X instance 1 should not exist in ModelYTestCase&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_model_x_instance_2_exists_not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Model X instance 2 should not exist in ModelYTestCase&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assertIsNone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;ModelX&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vm"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'__main__'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;#import logging&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;#log = logging.getLogger(__name__)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;#logging.basicConfig(level=logging.INFO)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="c1"&gt;#logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;unittest&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;unittest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;verbosity&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You can run the tests with &lt;strong&gt;&amp;quot;python test_app.py&amp;quot;&lt;/strong&gt;. You can uncomment the lines which enable &lt;em&gt;sqlalchemy.engine&lt;/em&gt; logging to see the SQL it is issuing.&lt;/p&gt;
&lt;p&gt;We must of course call the &lt;em&gt;setUpModule&lt;/em&gt; of the &lt;em&gt;flask_sqlalchemy_testing&lt;/em&gt; module in the start of our own &lt;em&gt;setUpModule&lt;/em&gt;. If you don't need to override it, remember to import it. The &lt;em&gt;tearDownModule&lt;/em&gt; also needs to be imported so that it will run. The same goes for &lt;em&gt;setUpClass/tearDownClass&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="download-the-code"&gt;
&lt;h2&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Download the Code&lt;/h2&gt;
&lt;p&gt;The code is available to download and use as you wish. Here it is:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/files/flask_sa_testing.tar.gz"&gt;flask_sa_testing.tar.gz&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I have used it, but not very extensively yet. Let me know if you find errors in it.&lt;/p&gt;
&lt;p&gt;Here are the commands to run it in a virtualenv:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
tar&lt;span class="w"&gt; &lt;/span&gt;zxvf&lt;span class="w"&gt; &lt;/span&gt;flask_sa_testing&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;flask_sa_testing&lt;span class="w"&gt;
&lt;/span&gt;virtualenv&lt;span class="w"&gt; &lt;/span&gt;virtualenv&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;virtualenv/bin/activate&lt;span class="w"&gt;
&lt;/span&gt;pip&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;requirements.txt&lt;span class="w"&gt;
&lt;/span&gt;createuser&lt;span class="w"&gt; &lt;/span&gt;-P&lt;span class="w"&gt; &lt;/span&gt;unittestuser&lt;span class="w"&gt;
&lt;/span&gt;createdb&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;unittestuser&lt;span class="w"&gt; &lt;/span&gt;unittestdb&lt;span class="w"&gt;
&lt;/span&gt;python&lt;span class="w"&gt; &lt;/span&gt;test_app.py
&lt;/pre&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Flask"></category><category term="PostgreSQL"></category><category term="Python"></category><category term="SQLAlchemy"></category></entry><entry><title>Ubuntu 14.04 Active Directory Authentication</title><link href="https://mikko.kortelainen.io/blog/ubuntu-14-04-active-directory-authentication/" rel="alternate"></link><published>2015-06-16T17:33:00+03:00</published><updated>2015-06-16T17:33:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2015-06-16:/blog/ubuntu-14-04-active-directory-authentication/</id><summary type="html">&lt;p&gt;In &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/ubuntu-12-04-active-directory-authentication/"&gt;a post&lt;/a&gt; a couple of years ago I gave an example on how to configure an Ubuntu 12.04 server to authenticate to Active Directory. Things used to be hard back then. Now we have the &lt;a class="reference external" href="http://www.freedesktop.org/software/realmd/"&gt;realmd&lt;/a&gt; realm enrollment manager to do the hard work of joining the host …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/ubuntu-12-04-active-directory-authentication/"&gt;a post&lt;/a&gt; a couple of years ago I gave an example on how to configure an Ubuntu 12.04 server to authenticate to Active Directory. Things used to be hard back then. Now we have the &lt;a class="reference external" href="http://www.freedesktop.org/software/realmd/"&gt;realmd&lt;/a&gt; realm enrollment manager to do the hard work of joining the host to an Active Directory domain, and the &lt;a class="reference external" href="https://fedorahosted.org/sssd/"&gt;System Security Services Daemon or SSSD&lt;/a&gt; to do the actual authentication and authorization work whenever it is needed. And things are much easier to configure and get running.&lt;/p&gt;
&lt;p&gt;Also in the mean time Microsoft has &lt;a class="reference external" href="https://msdn.microsoft.com/en-us/library/cc772571.aspx"&gt;deprecated the Identity Management for UNIX&lt;/a&gt; extension to Active Directory. It used to be used to manage POSIX attributes in the AD for use by UNIX clients. Luckily, the SSSD has a nice coherent way of mapping Windows user and group ids to UNIX ones so that POSIX attributes may not be needed at all in the AD anymore, making things more straighforward. If you still need to be able configure attributes by individual LDAP entry basis, you may need to look into &lt;a class="reference external" href="https://www.freeipa.org/page/Main_Page"&gt;FreeIPA&lt;/a&gt; and &lt;a class="reference external" href="https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Windows_Integration_Guide/id-views.html#id-views-id-ranges"&gt;ID Views&lt;/a&gt;. The automatic id mapping is not compatible with the old POSIX attributes in the sense that once you enable automatic id mapping, all the existing POSIX attributes are ignored.&amp;nbsp; So you may have to fix group memberships, for example, if your POSIX group memberships don't match the Windows group memberships (the Windows group memberships are the ones that will be used with id mapping). And of course all the uid numbers will be changed when you flip the switch and enable automatic id mapping.&lt;/p&gt;
&lt;p&gt;If you haven't been using POSIX attributes in the AD schema before, you don't have to worry about anything I said in the last paragraph. It just works.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="auto-toc simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#prerequisites" id="toc-entry-1"&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Prerequisites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#install-kerberos-client-sssd-and-tools" id="toc-entry-2"&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Install Kerberos client, SSSD and tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#authenticating-with-kerberos" id="toc-entry-3"&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;Authenticating with Kerberos&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#configuring-realmd" id="toc-entry-4"&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Configuring realmd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#joining-the-host-to-the-active-directory-domain" id="toc-entry-5"&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Joining The Host to the Active Directory Domain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#controlling-who-can-log-in" id="toc-entry-6"&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;Controlling Who Can Log In&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#enumerating-users-and-groups" id="toc-entry-7"&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Enumerating Users and Groups&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#automatic-home-directories" id="toc-entry-8"&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;Automatic Home Directories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#internals" id="toc-entry-9"&gt;9&amp;nbsp;&amp;nbsp;&amp;nbsp;Internals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#links" id="toc-entry-10"&gt;10&amp;nbsp;&amp;nbsp;&amp;nbsp;Links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="prerequisites"&gt;
&lt;h2&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Prerequisites&lt;/h2&gt;
&lt;p&gt;SSSD and realmd can be found in the Ubuntu repositories, so installation is easy. But a couple of things must be taken care of first.&lt;/p&gt;
&lt;p&gt;The first prerequisite is, make sure you are using your Active Directory DNS servers. They will be used to query the addresses of the domain controllers, and when the domain is joined, DNS records (forward and reverse) are added.&lt;/p&gt;
&lt;p&gt;The second prerequisite is that your time keeping should closely match the AD domain controller machines (usually within 5 minutes of each other). Use your domain controllers as NTP time sources, or at least use the same time sources for the domain controllers and the Linux hosts to keep their clocks very close to each other.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="install-kerberos-client-sssd-and-tools"&gt;
&lt;h2&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Install Kerberos client, SSSD and tools&lt;/h2&gt;
&lt;p&gt;Install the Kerberos client, the realm enrollment tool, the System Security Services Daemon, the AD client tool, and Samba tools:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
apt-get install krb5-user realmd sssd sssd-tools adcli samba-common-bin
&lt;/pre&gt;
&lt;p&gt;When prompted, type in your AD Kerberos realm. It should generally be your domain name in capital letters (“koo.fi” becomes “KOO.FI”). If your DNS is working properly, that should be all that is needed for the Kerberos client to work alright. Otherwise you may need to add your servers to &lt;em&gt;/etc/krb5.conf&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="authenticating-with-kerberos"&gt;
&lt;h2&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;Authenticating with Kerberos&lt;/h2&gt;
&lt;p&gt;Try getting a Kerberos ticket as domain administrator:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
kinit&lt;span class="w"&gt; &lt;/span&gt;administrator&amp;#64;KOO.FI&lt;span class="w"&gt;
&lt;/span&gt;klist
&lt;/pre&gt;
&lt;p&gt;The output of klist should look like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: administrator&amp;#64;KOO.FI

Valid starting     Expires            Service principal
06/16/15 16:23:22  06/17/15 02:23:22  krbtgt/KOO.FI&amp;#64;KOO.FI
    renew until 06/17/15 16:23:18
&lt;/pre&gt;
&lt;p&gt;That shows we now have a ticket valid for some hours, meaning the Kerberos authentication is working fine to the domain controller. We can proceed to configuring the realmd realm enrollment tool which will join us to the domain, and later use this ticket to actually execute the join operation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configuring-realmd"&gt;
&lt;h2&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Configuring realmd&lt;/h2&gt;
&lt;p&gt;Edit /etc/realmd.conf:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[service]
automatic-install = no

[users]
default-home = /home/%D/%U
default-shell = /bin/bash

[koo.fi]
computer-ou = OU=Linux,DC=koo,DC=fi
automatic-id-mapping = yes
fully-qualified-names = no
&lt;/pre&gt;
&lt;p&gt;The &lt;strong&gt;automatic-install=no&lt;/strong&gt; option will disable automatic installation of packages by realmd.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;default-home=/home/%D/%U&lt;/strong&gt; option will make the home directories of users be of form &lt;em&gt;/home/DOMAIN/USERNAME&lt;/em&gt;, eg. &lt;em&gt;/home/koo.fi/administrator&lt;/em&gt;. The &lt;strong&gt;default-shell&lt;/strong&gt; is the shell for users.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;computer-ou&lt;/strong&gt; option tells where the machine account will be added in AD.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;automatic-id-mapping=yes&lt;/strong&gt; option makes SSSD use automatic id mapping instead of user and group ids stored in POSIX attributes in AD. The SSSD automatic id mapping is intelligent in that it can &lt;a class="reference external" href="https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Windows_Integration_Guide/sssd-ad-integration.html#about-id-mapping"&gt;guarantee the same UNIX uid and gid on different hosts&lt;/a&gt; when all the hosts are using SSSD.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;fully-qualified-names=no&lt;/strong&gt; option will by default remove the domain part from user and group names. It may result in name collisions, but makes things easier for users since they only have to type in their username part and not the domain part every time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="joining-the-host-to-the-active-directory-domain"&gt;
&lt;h2&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Joining The Host to the Active Directory Domain&lt;/h2&gt;
&lt;p&gt;You can use the &amp;quot;realm discover&amp;quot; command to see if the Active Directory domain can be discovered. It requires avalid Kerberos ticket as a domain administrator.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
realm&lt;span class="w"&gt; &lt;/span&gt;discover&lt;span class="w"&gt; &lt;/span&gt;koo.fi
&lt;/pre&gt;
&lt;p&gt;Output should look like:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
koo.fi
  type: kerberos
  realm-name: KOO.FI
  domain-name: koo.fi
  configured: no
  server-software: active-directory
  client-software: sssd
  required-package: sssd-tools
  required-package: sssd
  required-package: libnss-sss
  required-package: libpam-sss
  required-package: adcli
  required-package: samba-common-bin
&lt;/pre&gt;
&lt;p&gt;We have all the required packages already installed, so let's just join:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
realm&lt;span class="w"&gt; &lt;/span&gt;join&lt;span class="w"&gt; &lt;/span&gt;koo.fi&lt;span class="w"&gt;
&lt;/span&gt;realm&lt;span class="w"&gt; &lt;/span&gt;list
&lt;/pre&gt;
&lt;p&gt;Output looks like:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
koo.fi
  type: kerberos
  realm-name: KOO.FI
  domain-name: koo.fi
  configured: kerberos-member
  server-software: active-directory
  client-software: sssd
  required-package: sssd-tools
  required-package: sssd
  required-package: libnss-sss
  required-package: libpam-sss
  required-package: adcli
  required-package: samba-common-bin
  login-formats: %U
  login-policy: allow-realm-logins
&lt;/pre&gt;
&lt;p&gt;After a successful join, you should be able to resolve individual users and groups using getent:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
getent&lt;span class="w"&gt; &lt;/span&gt;passwd&lt;span class="w"&gt; &lt;/span&gt;administrator&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# administrator:*:364000500:364000513:administrator:/home/koo.fi/administrator:/bin/bash
&lt;/span&gt;getent&lt;span class="w"&gt; &lt;/span&gt;group&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Domain Admins'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# domain admins:*:364000512:administrator&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;If you run into a &amp;quot;Failed to join the domain&amp;quot; error, try the join with user given as an option:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
realm&lt;span class="w"&gt; &lt;/span&gt;join&lt;span class="w"&gt; &lt;/span&gt;koo.fi&lt;span class="w"&gt; &lt;/span&gt;--user&lt;span class="o"&gt;=&lt;/span&gt;administrator
&lt;/pre&gt;
&lt;p&gt;If you run into a &amp;quot;Necessary packages are not installed&amp;quot; error, you may try to install packagekit:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;packagekit&lt;span class="w"&gt;
&lt;/span&gt;killall&lt;span class="w"&gt; &lt;/span&gt;aptd&lt;span class="w"&gt;
&lt;/span&gt;killall&lt;span class="w"&gt; &lt;/span&gt;realmd
&lt;/pre&gt;
&lt;p&gt;And then try again. There's a &lt;a class="reference external" href="https://bugs.launchpad.net/ubuntu/+source/realmd/+bug/1333694"&gt;bug in Launchpad&lt;/a&gt; about it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="controlling-who-can-log-in"&gt;
&lt;h2&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;Controlling Who Can Log In&lt;/h2&gt;
&lt;p&gt;Also at this point you should be able to log in with any AD user id by default. You can control who can and who cannot login with&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
realm&lt;span class="w"&gt; &lt;/span&gt;deny&lt;span class="w"&gt; &lt;/span&gt;--all&lt;span class="w"&gt;
&lt;/span&gt;realm&lt;span class="w"&gt; &lt;/span&gt;permit&lt;span class="w"&gt; &lt;/span&gt;administrator&lt;span class="w"&gt;
&lt;/span&gt;realm&lt;span class="w"&gt; &lt;/span&gt;permit&lt;span class="w"&gt; &lt;/span&gt;-g&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Domain Admins'&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You can see the changed policy and permitted logins with&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
realm&lt;span class="w"&gt; &lt;/span&gt;list
&lt;/pre&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
koo.fi
  type: kerberos
  realm-name: KOO.FI
  domain-name: koo.fi
  configured: kerberos-member
  server-software: active-directory
  client-software: sssd
  required-package: sssd-tools
  required-package: sssd
  required-package: libnss-sss
  required-package: libpam-sss
  required-package: adcli
  required-package: samba-common-bin
  login-formats: %U
  login-policy: allow-permitted-logins
  permitted-logins: administrator
  permitted-groups: Domain Admins
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="enumerating-users-and-groups"&gt;
&lt;h2&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Enumerating Users and Groups&lt;/h2&gt;
&lt;p&gt;The SSSD configuration file &lt;em&gt;/etc/sssd/sssd.conf&lt;/em&gt; was generated by the realm join command and will look something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[sssd]
domains = koo.fi
config_file_version = 2
services = nss, pam

[domain/koo.fi]
ad_domain = koo.fi
krb5_realm = KOO.FI
realmd_tags = manages-system joined-with-adcli
cache_credentials = True
id_provider = ad
krb5_store_password_if_offline = True
default_shell = /bin/bash
ldap_id_mapping = True
use_fully_qualified_names = False
fallback_homedir = /home/%d/%u
access_provider = ad
&lt;/pre&gt;
&lt;p&gt;For performance reasons by default SSSD will not try to enumerate every user and group from AD, but will only query for them when requested. If you want to enable enumeration, add:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
enumerate = True
&lt;/pre&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;under your domain stanza in sssd.conf (and &amp;quot;restart sssd&amp;quot;). It is quick for a small directory, but may be slow for a large one. It can be handy for debugging, as you can list all users and groups with&lt;/div&gt;
&lt;div class="line"&gt;&amp;quot;getent passwd&amp;quot; and &amp;quot;getent group&amp;quot;.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="automatic-home-directories"&gt;
&lt;h2&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;Automatic Home Directories&lt;/h2&gt;
&lt;p&gt;To create home directories at first login, add a &lt;em&gt;pam_mkhomedir.so&lt;/em&gt; line in &lt;em&gt;/etc/pam.d/common-session&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
session [default=1]   pam_permit.so
session requisite     pam_deny.so
session required      pam_permit.so
session optional      pam_umask.so
session required      pam_unix.so
session required      pam_mkhomedir.so  skel=/etc/skel umask=0022
session optional      pam_sss.so
session optional      pam_systemd.so
&lt;/pre&gt;
&lt;p&gt;That's basicly it. At this point you should have a fully functioning AD login for selected users on your Ubuntu server.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="internals"&gt;
&lt;h2&gt;9&amp;nbsp;&amp;nbsp;&amp;nbsp;Internals&lt;/h2&gt;
&lt;p&gt;The &amp;quot;machine account&amp;quot; Kerberos principal is saved into the file &lt;em&gt;/etc/krb5.keytab&lt;/em&gt;. You can list&amp;nbsp;its contents with &amp;quot;klist -kt /etc/krb5.keytab&amp;quot;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Keytab name: FILE:/etc/krb5.keytab
KVNO Timestamp         Principal
---- ----------------- --------------------------------------------------------
   3 06/16/15 17:35:57 host/server.koo.fi&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/server.koo.fi&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/server.koo.fi&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/server.koo.fi&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/server.koo.fi&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/SERVER&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/SERVER&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/SERVER&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/SERVER&amp;#64;KOO.FI
   3 06/16/15 17:35:57 host/SERVER&amp;#64;KOO.FI
   3 06/16/15 17:35:57 SERVER$&amp;#64;KOO.FI
   3 06/16/15 17:35:57 SERVER$&amp;#64;KOO.FI
   3 06/16/15 17:35:57 SERVER$&amp;#64;KOO.FI
   3 06/16/15 17:35:57 SERVER$&amp;#64;KOO.FI
   3 06/16/15 17:35:57 SERVER$&amp;#64;KOO.FI
&lt;/pre&gt;
&lt;p&gt;Here the local server's hostname is &amp;quot;server&amp;quot;. SSSD uses this&amp;nbsp;keytab file and the principals in it to periodically refres Kerberos tickets, which are saved in the file *&amp;nbsp;/var/lib/sss/db/ccache_&amp;lt;REALM&amp;gt;*. For example &amp;quot;klist -c /var/lib/sss/db/ccache_KOO.FI&amp;quot;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Ticket cache: FILE:/var/lib/sss/db/ccache_KOO.FI
Default principal: SERVER$&amp;#64;KOO.FI

Valid starting     Expires            Service principal
06/22/15 13:22:52  06/22/15 23:22:52  krbtgt/KOO.FI&amp;#64;KOO.FI
    renew until 06/23/15 13:22:52
06/22/15 13:22:52  06/22/15 23:22:52  ldap/dc1.koo.fi&amp;#64;
    renew until 06/23/15 13:22:52
06/22/15 13:22:52  06/22/15 23:22:52  ldap/dc1.koo.fi&amp;#64;KOO.FI
    renew until 06/23/15 13:22:52
&lt;/pre&gt;
&lt;p&gt;Here we can see three active tickets. These are used to authenticate the host to AD and fetch information from LDAP.&lt;/p&gt;
&lt;p&gt;There are also &lt;em&gt;.ldb&lt;/em&gt; files under &lt;em&gt;/var/lib/sss/db&lt;/em&gt; which you can dump using &lt;em&gt;tdbdump&lt;/em&gt; tool from the &lt;em&gt;tdb-tools&lt;/em&gt; package if you want to see internal configuration and cached data.&lt;/p&gt;
&lt;p&gt;The IP address of the AD domain controller currently used as KDC can be found in &lt;em&gt;/var/lib/sss/pubconf/kdcinfo.&amp;lt;REALM&amp;gt;&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="links"&gt;
&lt;h2&gt;10&amp;nbsp;&amp;nbsp;&amp;nbsp;Links&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://help.ubuntu.com/lts/serverguide/sssd-ad.html"&gt;Ubuntu Server Guide: SSSD and Active Directory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.ubuntugeek.com/how-to-join-ubuntu-14-04-to-active-directory-using-realmd.html"&gt;How to Join Ubuntu 14.04 to Active directory using Realmd&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://www.samba.org/~ab/sambaxp/2015/freeipa_idviews.pdf"&gt;Handling POSIX attributes for trusted Active Directory users and groups in FreeIPA (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Active Directory"></category><category term="Authentication"></category><category term="Kerberos"></category><category term="Ubuntu"></category><category term="Uncategorized"></category></entry><entry><title>VPN between StrongSwan and SonicWall</title><link href="https://mikko.kortelainen.io/blog/vpn-between-strongswan-and-sonicwall/" rel="alternate"></link><published>2015-04-04T18:36:00+03:00</published><updated>2015-04-04T18:36:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2015-04-04:/blog/vpn-between-strongswan-and-sonicwall/</id><summary type="html">&lt;p&gt;Here's how to create a site-to-site VPN between StrongSwan and SonicWall. This
has been tested with Ubuntu 14.04 and StrongSwan 5.1.2, and SonicWall with
SonicOS 5.9 at the other end.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="auto-toc simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#network-topology" id="toc-entry-1"&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Network Topology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#strongswan" id="toc-entry-2"&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;StrongSwan&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#install" id="toc-entry-3"&gt;2.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#configure" id="toc-entry-4"&gt;2.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Configure&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#etc-ipsec-conf" id="toc-entry-5"&gt;2.2 …&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Here's how to create a site-to-site VPN between StrongSwan and SonicWall. This
has been tested with Ubuntu 14.04 and StrongSwan 5.1.2, and SonicWall with
SonicOS 5.9 at the other end.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="auto-toc simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#network-topology" id="toc-entry-1"&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Network Topology&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#strongswan" id="toc-entry-2"&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;StrongSwan&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#install" id="toc-entry-3"&gt;2.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Install&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#configure" id="toc-entry-4"&gt;2.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Configure&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#etc-ipsec-conf" id="toc-entry-5"&gt;2.2.1&amp;nbsp;&amp;nbsp;&amp;nbsp;/etc/ipsec.conf:&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#etc-ipsec-secrets" id="toc-entry-6"&gt;2.2.2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/etc/ipsec.secrets:&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#start-ipsec-service" id="toc-entry-7"&gt;2.3&amp;nbsp;&amp;nbsp;&amp;nbsp;Start IPsec Service&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#sonicwall" id="toc-entry-8"&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;SonicWall&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#vpn-connection-general" id="toc-entry-9"&gt;3.1&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; General&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#vpn-connection-network" id="toc-entry-10"&gt;3.2&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; Network&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#vpn-connection-proposals" id="toc-entry-11"&gt;3.3&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; Proposals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#vpn-connection-advanced" id="toc-entry-12"&gt;3.4&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; Advanced&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#firewall-rules" id="toc-entry-13"&gt;3.5&amp;nbsp;&amp;nbsp;&amp;nbsp;Firewall Rules&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#check-status" id="toc-entry-14"&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Check Status&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="network-topology"&gt;
&lt;h2&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Network Topology&lt;/h2&gt;
&lt;p&gt;In this example, we will route traffic between two networks that are located at
different sites. Our example network topology looks like this:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/Valinta_084.png"&gt;&lt;img alt="Network topology" class="alignnone size-full wp-image-1126" src="https://mikko.kortelainen.io/blog/files/Valinta_084.png" style="width: 292px; height: 598px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The VPN tunnel will encrypt all traffic between the endpoints. The green
networks will be routed to each other through the encrypted tunnel.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="strongswan"&gt;
&lt;h2&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;StrongSwan&lt;/h2&gt;
&lt;div class="section" id="install"&gt;
&lt;h3&gt;2.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Install&lt;/h3&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;strongswan
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="configure"&gt;
&lt;h3&gt;2.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Configure&lt;/h3&gt;
&lt;p&gt;Two files need editing: &lt;em&gt;/etc/ipsec.conf&lt;/em&gt; and &lt;em&gt;/etc/ipsec.secrets&lt;/em&gt;. The first
one is the configuration file, and the second one contains the pre-shared key
the endpoints will use to authenticate each other.&lt;/p&gt;
&lt;div class="section" id="etc-ipsec-conf"&gt;
&lt;h4&gt;2.2.1&amp;nbsp;&amp;nbsp;&amp;nbsp;/etc/ipsec.conf:&lt;/h4&gt;
&lt;pre class="code literal-block"&gt;
conn sonicwall
  # This server
  left=192.168.1.1
  leftid=192.168.1.1
  # The network behind this server
  leftsourceip=10.0.1.1
  leftsubnet=10.0.1.0/24
  # The remote SonicWall
  right=192.168.2.1
  rightid=192.168.2.1
  # The network behind remote SonicWall
  rightsubnet=10.0.2.0/24
  # Connection parameters
  keyexchange=ikev2
  authby=psk
  ike=aes256-sha1-modp2048
  esp=aes256-sha1-modp2048
  auto=start
&lt;/pre&gt;
&lt;p&gt;We use IKEv2 for key exchange, with AES-256 for encryption and SHA-1 for
hashing. A 2048-bit key means Diffie-Hellman group 14. Authentication is done
using a pre-shared key. The connection will be started automatically at start.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="etc-ipsec-secrets"&gt;
&lt;h4&gt;2.2.2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;/etc/ipsec.secrets:&lt;/h4&gt;
&lt;pre class="code literal-block"&gt;
192.168.1.1 192.168.2.1 : PSK &amp;quot;XXXSECRETXXX&amp;quot;
&lt;/pre&gt;
&lt;p&gt;There should be one line per connection in that file. The format, when using
pre-shared keys, is this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
local_ip remote_ip : PSK &amp;quot;your password&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Please set your password to a random string.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="start-ipsec-service"&gt;
&lt;h3&gt;2.3&amp;nbsp;&amp;nbsp;&amp;nbsp;Start IPsec Service&lt;/h3&gt;
&lt;p&gt;To start the service:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;service&lt;span class="w"&gt; &lt;/span&gt;ipsec&lt;span class="w"&gt; &lt;/span&gt;start
&lt;/pre&gt;
&lt;p&gt;To make it start at boot:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;update-rc.d&lt;span class="w"&gt; &lt;/span&gt;ipsec&lt;span class="w"&gt; &lt;/span&gt;defaults
&lt;/pre&gt;
&lt;p&gt;To see the status, run:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;ipsec&lt;span class="w"&gt; &lt;/span&gt;statusall
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
Status of IKE charon daemon (strongSwan 5.1.2, Linux 3.13.0-48-generic, x86_64):
  uptime: 92 seconds, since Apr 04 14:45:29 2015
  malloc: sbrk 2433024, mmap 0, used 351664, free 2081360
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 2
  loaded plugins: charon test-vectors aes rc2 sha1 sha2 md4 md5 random nonce x509
  revocation constraints pkcs1 pkcs7 pkcs8 pkcs12 pem openssl xcbc cmac hmac ctr
  ccm gcm attr kernel-netlink resolve socket-default stroke updown eap-identity
  addrblock
Listening IP addresses:
  192.168.1.1
  10.0.1.1
Connections:
   sonicwall:  192.168.1.1...192.168.2.1  IKEv2
   sonicwall:   local:  [192.168.1.1] uses pre-shared key authentication
   sonicwall:   remote: [192.168.2.1] uses pre-shared key authentication
   sonicwall:   child:  10.0.1.0/24 === 10.0.2.0/24 TUNNEL
&lt;/pre&gt;
&lt;p&gt;However, you need to configure the other endpoint first before you will see an
active connection and a security association.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="sonicwall"&gt;
&lt;h2&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;SonicWall&lt;/h2&gt;
&lt;p&gt;Go to VPN &amp;gt; Settings. Add a new VPN connection.&lt;/p&gt;
&lt;div class="section" id="vpn-connection-general"&gt;
&lt;h3&gt;3.1&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; General&lt;/h3&gt;
&lt;p&gt;The &amp;quot;Shared Secret&amp;quot; field should contain the same random string you put into the
&lt;em&gt;/etc/ipsec.secrets&lt;/em&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/Valinta_075.png"&gt;&lt;img alt="VPN - General" class="alignnone wp-image-1120 size-full" src="https://mikko.kortelainen.io/blog/files/Valinta_075.png" style="width: 671px; height: 435px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="vpn-connection-network"&gt;
&lt;h3&gt;3.2&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; Network&lt;/h3&gt;
&lt;p&gt;The remote network zone should be a &amp;quot;VPN&amp;quot; zone.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/Valinta_079.png"&gt;&lt;img alt="VPN - Remote" class="alignnone size-full wp-image-1122" src="https://mikko.kortelainen.io/blog/files/Valinta_079.png" style="width: 681px; height: 343px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="vpn-connection-proposals"&gt;
&lt;h3&gt;3.3&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; Proposals&lt;/h3&gt;
&lt;p&gt;For the proposal we must match the parameters in &lt;em&gt;/etc/ipsec.conf&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/Valinta_080.png"&gt;&lt;img alt="VPN - Proposal" class="alignnone size-full wp-image-1123" src="https://mikko.kortelainen.io/blog/files/Valinta_080.png" style="width: 678px; height: 500px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="vpn-connection-advanced"&gt;
&lt;h3&gt;3.4&amp;nbsp;&amp;nbsp;&amp;nbsp;VPN Connection &amp;gt; Advanced&lt;/h3&gt;
&lt;p&gt;In the advanced tab I enabled keep-alive.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/Valinta_081.png"&gt;&lt;img alt="VPN - Advanced" class="alignnone size-full wp-image-1124" src="https://mikko.kortelainen.io/blog/files/Valinta_081.png" style="width: 674px; height: 539px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="firewall-rules"&gt;
&lt;h3&gt;3.5&amp;nbsp;&amp;nbsp;&amp;nbsp;Firewall Rules&lt;/h3&gt;
&lt;p&gt;Also, remember to add firewall rules to allow traffic to flow between networks
in SonicWall. Also do the same if you have Iptables in use on the StrongSwan
server.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="check-status"&gt;
&lt;h2&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Check Status&lt;/h2&gt;
&lt;p&gt;At this point, the SonicWall should show a green dot on the VPN policy line you
created. If not, check the SonicWall log for error messages.&lt;/p&gt;
&lt;p&gt;You should also be able to see an active security association on the StrongSwan
host with:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;ipsec&lt;span class="w"&gt; &lt;/span&gt;statusall
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
Status of IKE charon daemon (strongSwan 5.1.2, Linux 3.13.0-48-generic, x86_64):
  uptime: 92 seconds, since Apr 04 14:45:29 2015
  malloc: sbrk 2433024, mmap 0, used 351664, free 2081360
  worker threads: 11 of 16 idle, 5/0/0/0 working, job queue: 0/0/0/0, scheduled: 2
  loaded plugins: charon test-vectors aes rc2 sha1 sha2 md4 md5 random nonce x509
  revocation constraints pkcs1 pkcs7 pkcs8 pkcs12 pem openssl xcbc cmac hmac ctr
  ccm gcm attr kernel-netlink resolve socket-default stroke updown eap-identity
  addrblock
Listening IP addresses:
  192.168.1.1
  10.0.1.1
Connections:
   sonicwall:  192.168.1.1...192.168.2.1  IKEv2
   sonicwall:   local:  [192.168.1.1] uses pre-shared key authentication
   sonicwall:   remote: [192.168.2.1] uses pre-shared key authentication
   sonicwall:   child:  10.0.1.0/24 === 10.0.2.0/24 TUNNEL
Security Associations (1 up, 0 connecting):
   sonicwall[2]: ESTABLISHED 86 seconds ago, 192.168.1.1[192.168.1.1]...192.168.2.1[192.168.2.1]
   sonicwall[2]: IKEv2 SPIs: XXX XXX*, pre-shared key reauthentication in 2 hours
   sonicwall[2]: IKE proposal: AES_CBC_256/HMAC_SHA1_96/PRF_HMAC_SHA1/MODP_2048
   sonicwall{2}:  INSTALLED, TUNNEL, ESP SPIs: XXX XXX
   sonicwall{2}:  AES_CBC_256/HMAC_SHA1_96, 7224 bytes_i (86 pkts, 1s ago), 7224 bytes_o (86 pkts, 1s ago), rekeying in 44 minutes
   sonicwall{2}:   10.0.1.0/24 === 10.0.2.0/24
&lt;/pre&gt;
&lt;p&gt;You can control your tunnel(s) with these commands:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;ipsec&lt;span class="w"&gt; &lt;/span&gt;down&lt;span class="w"&gt; &lt;/span&gt;sonicwall&lt;span class="w"&gt;
&lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;ipsec&lt;span class="w"&gt; &lt;/span&gt;up&lt;span class="w"&gt; &lt;/span&gt;sonicwall
&lt;/pre&gt;
&lt;p&gt;See log files &lt;em&gt;/var/log/auth.log&lt;/em&gt; and &lt;em&gt;/var/log/syslog&lt;/em&gt; for log messages.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="SonicWall"></category><category term="StrongSwan"></category><category term="Ubuntu"></category></entry><entry><title>OpenStreetMap Nominatim Server for Geocoding</title><link href="https://mikko.kortelainen.io/blog/openstreetmap-nominatim-server-for-geocoding/" rel="alternate"></link><published>2015-03-19T18:04:00+02:00</published><updated>2015-03-19T18:04:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2015-03-19:/blog/openstreetmap-nominatim-server-for-geocoding/</id><summary type="html">&lt;p&gt;Here's how to install the OpenStreetMap Nominatim service on your own server. It
can be used to geocode and reverse geocode addresses and map coordinates. You
will also get a web interface which loads map tiles from openstreetmap.org while
doing geocoding requests using your own server.&lt;/p&gt;
&lt;p&gt;I was faced …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's how to install the OpenStreetMap Nominatim service on your own server. It
can be used to geocode and reverse geocode addresses and map coordinates. You
will also get a web interface which loads map tiles from openstreetmap.org while
doing geocoding requests using your own server.&lt;/p&gt;
&lt;p&gt;I was faced with thousands of geocoding requests per hour, and with such a high
volume it is not wise to burden the global OSM servers. Even with aggressive
caching it would have potentially been too much.&lt;/p&gt;
&lt;p&gt;I will use Ubuntu 14.04 LTS as the platform. Just a basic install with ssh
server. We will install Apache to serve http requests. Make sure you have enough
disk space and RAM to hold the data and serve it efficiently. I used the Finland
extract, which was about a 200 MB download. The resulting database was 26 GB
after importing, indexing and adding Wikipedia data. The Wikipedia data probably
actually took more disk space than the OSM data. My server has 4 GB RAM, which
seems to be enough for this small data set.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="auto-toc simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#software-requirements" id="toc-entry-1"&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Software requirements&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#kernel-tuning" id="toc-entry-2"&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Kernel tuning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#postgresql-tuning" id="toc-entry-3"&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;PostgreSQL tuning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#dedicated-user" id="toc-entry-4"&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Dedicated user&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#database-users" id="toc-entry-5"&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Database users&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#download-and-compile-nominatim" id="toc-entry-6"&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;Download and Compile Nominatim&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#clone-the-repository-from-github" id="toc-entry-7"&gt;6.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Clone the Repository from Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#compile-nominatim" id="toc-entry-8"&gt;6.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Compile Nominatim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#configure-local-settings" id="toc-entry-9"&gt;6.3&amp;nbsp;&amp;nbsp;&amp;nbsp;Configure Local Settings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#download-data" id="toc-entry-10"&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Download Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#import-data" id="toc-entry-11"&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;Import Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#database-production-settings" id="toc-entry-12"&gt;9&amp;nbsp;&amp;nbsp;&amp;nbsp;Database Production Settings&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#create-the-web-site" id="toc-entry-13"&gt;10&amp;nbsp;&amp;nbsp;&amp;nbsp;Create the Web Site&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#apache-configuration" id="toc-entry-14"&gt;10.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Apache configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#install-the-nominatim-web-site" id="toc-entry-15"&gt;10.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Install the Nominatim Web Site&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#enable-osm-updates" id="toc-entry-16"&gt;11&amp;nbsp;&amp;nbsp;&amp;nbsp;Enable OSM Updates&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#wrap-up" id="toc-entry-17"&gt;12&amp;nbsp;&amp;nbsp;&amp;nbsp;Wrap Up&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#useful-links" id="toc-entry-18"&gt;12.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Useful links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="software-requirements"&gt;
&lt;h2&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Software requirements&lt;/h2&gt;
&lt;p&gt;PostgreSQL with PostGIS extension:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;postgresql&lt;span class="w"&gt; &lt;/span&gt;postgis&lt;span class="w"&gt; &lt;/span&gt;postgresql-contrib&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;postgresql-server-dev-9.3&lt;span class="w"&gt; &lt;/span&gt;postgresql-9.3-postgis-2.1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;postgresql-doc-9.3&lt;span class="w"&gt; &lt;/span&gt;postgis-doc
&lt;/pre&gt;
&lt;p&gt;Apache with PHP5:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;apache2&lt;span class="w"&gt; &lt;/span&gt;php5&lt;span class="w"&gt; &lt;/span&gt;php-pear&lt;span class="w"&gt; &lt;/span&gt;php5-pgsql&lt;span class="w"&gt; &lt;/span&gt;php5-json&lt;span class="w"&gt; &lt;/span&gt;php-db
&lt;/pre&gt;
&lt;p&gt;Git and various tools:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;wget&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;autoconf-archive&lt;span class="w"&gt; &lt;/span&gt;build-essential&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;automake&lt;span class="w"&gt; &lt;/span&gt;gcc&lt;span class="w"&gt; &lt;/span&gt;proj-bin
&lt;/pre&gt;
&lt;p&gt;Tool for handling OpenStreetMap data:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;osmosis
&lt;/pre&gt;
&lt;p&gt;Needed libraries:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;libxml2-dev&lt;span class="w"&gt; &lt;/span&gt;libgeos-dev&lt;span class="w"&gt; &lt;/span&gt;libpq-dev&lt;span class="w"&gt; &lt;/span&gt;libbz2-dev&lt;span class="w"&gt; &lt;/span&gt;libtool&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;automake&lt;span class="w"&gt; &lt;/span&gt;libproj-dev&lt;span class="w"&gt; &lt;/span&gt;libboost-dev&lt;span class="w"&gt; &lt;/span&gt;libboost-system-dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;libboost-filesystem-dev&lt;span class="w"&gt; &lt;/span&gt;libboost-thread-dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;libgeos-c1&lt;span class="w"&gt; &lt;/span&gt;libgeos++-dev&lt;span class="w"&gt; &lt;/span&gt;lua5.2&lt;span class="w"&gt; &lt;/span&gt;liblua5.2-dev&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;libprotobuf-c0-dev&lt;span class="w"&gt; &lt;/span&gt;protobuf-c-compiler
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="kernel-tuning"&gt;
&lt;h2&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Kernel tuning&lt;/h2&gt;
&lt;p&gt;We must increase kernel shared memory limits. Also we'll reduce swappiness and
set the kernel memory overcommit to be a bit more conservative. Make sure you
have anough swap space, more than physical memory is a good idea.&lt;/p&gt;
&lt;p&gt;These have been estimated using 4 GB RAM.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sysctl&lt;span class="w"&gt; &lt;/span&gt;-w&lt;span class="w"&gt; &lt;/span&gt;kernel.shmmax&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;4404019200&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;sysctl&lt;span class="w"&gt; &lt;/span&gt;-w&lt;span class="w"&gt; &lt;/span&gt;kernel.shmall&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1075200&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;sysctl&lt;span class="w"&gt; &lt;/span&gt;vm.overcommit_memory&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;sysctl&lt;span class="w"&gt; &lt;/span&gt;vm.swappiness&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;kernel.shmmax=4404019200&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/sysctl.conf&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;kernel.shmall=1075200&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/sysctl.conf&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vm.overcommit_memory=2&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/sysctl.conf&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;vm.swappiness=10&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/etc/sysctl.conf
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="postgresql-tuning"&gt;
&lt;h2&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;PostgreSQL tuning&lt;/h2&gt;
&lt;p&gt;The following directives were set in &lt;em&gt;/etc/postgresql/9.3/main/postgresql.conf&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;shared_buffers&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;2048MB&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;work_mem&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;50MB&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;maintenance_work_mem&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;1024M&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;fsync&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;off&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# dangerous!
&lt;/span&gt;&lt;span class="nv"&gt;synchronous_commit&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;off&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;full_page_writes&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;off&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# dangerous!
&lt;/span&gt;&lt;span class="nv"&gt;checkpoint_segments&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;checkpoint_timeout&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;10min&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;checkpoint_completion_target&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.9&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;effective_cache_size&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;2048M
&lt;/pre&gt;
&lt;p&gt;The buffer and memory values depend on your available RAM so you should set sane
values accordingly.&amp;nbsp; These are good for 4 GB RAM.&lt;/p&gt;
&lt;p&gt;There are two truly dangerous settings here. Setting &lt;strong&gt;fsync&lt;/strong&gt; off will cause
PostgreSQL to report successful commits before the disk has confirmed the data
has been written successfully. Setting &lt;strong&gt;full_page_writes&lt;/strong&gt; off exposes the
database to the possibility of partially updated data in case of power failure.
These options are used here only for the duration of the initial import, because
setting them so makes the import much faster. Fsync and full page writes must be
turned back on after the import to ensure database consistency.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;synchronous_commit&lt;/strong&gt; also jeopardizes the durability of committed
transactions by reporting successful commits to clients asynchronously, meaning
that the transaction may not have been fully written to disk. It does not
compromize&amp;nbsp; consistency as the two previous directives discussed. It just means
that&amp;nbsp;in the case of power failure, some recent transactions that were already
reported to the client as having been committed, may in fact be aborted and
rolled back. The database will still be in a consistent state. We'll leave it
off because it speeds up the queries, and we don't really care about it in this
database. We can always rebuild it from scratch. But if you have other important
databases in the same database cluster, I would recommend turning it back on as
well, since the setting is cluster-wide.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;maintenance_work_mem&lt;/strong&gt; will also be reduced to a lower value later, after
the import.&lt;/p&gt;
&lt;p&gt;Restart PostgreSQL to apply changes:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
pg_ctlcluster&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="dedicated-user"&gt;
&lt;h2&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Dedicated user&lt;/h2&gt;
&lt;p&gt;We'll install the software under this user's home directory (user id &amp;quot;nominatim&amp;quot;).&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
useradd&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'OpenStreetMap Nominatim'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/bin/bash&lt;span class="w"&gt; &lt;/span&gt;nominatim
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="database-users"&gt;
&lt;h2&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Database users&lt;/h2&gt;
&lt;p&gt;We will also make &amp;quot;nominatim&amp;quot; a database user, as well as the already created
&amp;quot;www-data&amp;quot; (created by the apache2 package).&lt;/p&gt;
&lt;p&gt;Nominatim will be a superuser and www-data will be a regular one.&lt;/p&gt;
&lt;p&gt;This must be done as a database administrator. The &amp;quot;postgres&amp;quot; user by default is
one (root is not). Change user:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;postgres
&lt;/pre&gt;
&lt;p&gt;Create database users:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
createuser -sdRe nominatim
createuser -SDRe www-data
exit
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="download-and-compile-nominatim"&gt;
&lt;h2&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;Download and Compile Nominatim&lt;/h2&gt;
&lt;p&gt;Su to user nominatim:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;nominatim
&lt;/pre&gt;
&lt;p&gt;Set some environment variables. We'll use these later. These are the download
locations for files and updates. Lines 3 and 4 below are for Finland. Customize
to your needs.&lt;/p&gt;
&lt;p&gt;Also set the BASE_URL to point to your server and install directory. The last
forward slash seems to be important.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;WIKIPEDIA_ARTICLES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://www.nominatim.org/data/wikipedia_article.sql.bin&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;WIKIPEDIA_REDIRECTS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://www.nominatim.org/data/wikipedia_redirect.sql.bin&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;OSM_LATEST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://download.geofabrik.de/europe/finland-latest.osm.pbf&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;OSM_UPDATES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://download.geofabrik.de/europe/finland-updates&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;BASE_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://maps.example.org/nominatim/&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You can browse available areas at &lt;a class="reference external" href="http://download.geofabrik.de/"&gt;download.geofabrik.de&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="clone-the-repository-from-github"&gt;
&lt;h3&gt;6.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Clone the Repository from Github&lt;/h3&gt;
&lt;p&gt;We will use the release 2.3 branch:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;--recursive&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;https://github.com/twain47/Nominatim.git&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;--branch&lt;span class="w"&gt; &lt;/span&gt;release_2.3&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Nominatim
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;--recursive&lt;/em&gt; option is needed to clone everything, because the repository
contains submodules.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="compile-nominatim"&gt;
&lt;h3&gt;6.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Compile Nominatim&lt;/h3&gt;
&lt;p&gt;Simply:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
./autogen.sh&lt;span class="w"&gt;
&lt;/span&gt;./configure&lt;span class="w"&gt;
&lt;/span&gt;make
&lt;/pre&gt;
&lt;p&gt;If there were no errors, we are good. In case of missing libraries, check that
you installed all requirements earlier.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-local-settings"&gt;
&lt;h3&gt;6.3&amp;nbsp;&amp;nbsp;&amp;nbsp;Configure Local Settings&lt;/h3&gt;
&lt;p&gt;Some required settings should go to &lt;em&gt;~/Nominatim/settings/local.php&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;settings/local.php&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;EOF
&amp;lt;?php
// Paths
&amp;#64;define('CONST_Postgresql_Version', '9.3');
&amp;#64;define('CONST_Postgis_Version', '2.1');
&amp;#64;define('CONST_Website_BaseURL', '$BASE_URL');

// Update process
&amp;#64;define('CONST_Replication_Url', '$OSM_UPDATES');
&amp;#64;define('CONST_Replication_MaxInterval', '86400');
&amp;#64;define('CONST_Replication_Update_Interval', '86400');
&amp;#64;define('CONST_Replication_Recheck_Interval', '900');
?&amp;gt;
EOF&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The last four definitions are only required if you are going to do incremental
updates.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="download-data"&gt;
&lt;h2&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Download Data&lt;/h2&gt;
&lt;p&gt;OpenStreetMap data (about 200 MB for Finland):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
wget&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;data/latest.osm.pbf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$OSM_LATEST&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The OSM data is all that is really required. The rest below are optional.&lt;/p&gt;
&lt;p&gt;Wikipedia data (about 1.4 GB):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
wget&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;data/wikipedia_article.sql.bin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WIKIPEDIA_ARTICLES&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;wget&lt;span class="w"&gt; &lt;/span&gt;-O&lt;span class="w"&gt; &lt;/span&gt;data/wikipedia_redirect.sql.bin&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WIKIPEDIA_REDIRECTS&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Special phrases for country codes and names (very small):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
./utils/specialphrases.php&lt;span class="w"&gt; &lt;/span&gt;--countries&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;data/specialphrases_countries.sql
&lt;/pre&gt;
&lt;p&gt;Special search phrases (a few megabytes):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
./utils/specialphrases.php&lt;span class="w"&gt; &lt;/span&gt;--wiki-import&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;data/specialphrases.sql
&lt;/pre&gt;
&lt;p&gt;Next we'll import all this stuff into the database.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="import-data"&gt;
&lt;h2&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;Import Data&lt;/h2&gt;
&lt;p&gt;The utils/setup.php will create a new database called &amp;quot;nominatim&amp;quot; and import the
given .pbf file into it. This will take a long time depending on your PostgreSQL
settings, available memory, disk speed and size of dataset. The full planet can
take days to import on modern hardware. My small dataset took a bit over two
hours.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
./utils/setup.php&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;--osm-file&lt;span class="w"&gt; &lt;/span&gt;data/latest.osm.pbf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;--all&lt;span class="w"&gt; &lt;/span&gt;--osm2pgsql-cache&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;setup.log
&lt;/pre&gt;
&lt;p&gt;The messages will be saved into &lt;em&gt;setup.log&lt;/em&gt; in case you need to look at them
later.&lt;/p&gt;
&lt;p&gt;If you had the Wikipedia data downloaded, the setup should have imported that
automatically and told you about it. You can import the special phrases data if
you downloaded it earlier using these commands:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
psql&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;nominatim&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;data/specialphrases_countries.sql&lt;span class="w"&gt;
&lt;/span&gt;psql&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;nominatim&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;data/specialphrases.sql
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="database-production-settings"&gt;
&lt;h2&gt;9&amp;nbsp;&amp;nbsp;&amp;nbsp;Database Production Settings&lt;/h2&gt;
&lt;p&gt;Now that the import is done, it is time to configure the database to settings
that are suitable for production use. The following changes were made in
&lt;em&gt;/etc/postgresql/9.3/main/postgresql.conf&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
maintenance_work_mem          = 128M
fsync                         = on
full_page_writes              = on
&lt;/pre&gt;
&lt;p&gt;You should also set the &lt;strong&gt;synchronous_commit&lt;/strong&gt; directive to on if you have other
databases running on this same database cluster. See the PostgreSQL Tuning
section earlier in this post.&lt;/p&gt;
&lt;p&gt;Apply changes:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
pg_ctlcluster&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;9&lt;/span&gt;.3&lt;span class="w"&gt; &lt;/span&gt;main&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="create-the-web-site"&gt;
&lt;h2&gt;10&amp;nbsp;&amp;nbsp;&amp;nbsp;Create the Web Site&lt;/h2&gt;
&lt;p&gt;The following commands have to be run as root.&lt;/p&gt;
&lt;p&gt;Create a directory to install the site into and set permissions:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
mkdir&lt;span class="w"&gt; &lt;/span&gt;/var/www/html/nominatim&lt;span class="w"&gt;
&lt;/span&gt;chown&lt;span class="w"&gt; &lt;/span&gt;nominatim:www-data&lt;span class="w"&gt; &lt;/span&gt;/var/www/html/nominatim&lt;span class="w"&gt;
&lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;755&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/var/www/html/nominatim&lt;span class="w"&gt;
&lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;g+s&lt;span class="w"&gt; &lt;/span&gt;/var/www/html/nominatim
&lt;/pre&gt;
&lt;p&gt;Ask bots to keep out:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
cat&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;/var/www/html/nominatim/robots.txt&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;'EOF'
User-agent: *
Disallow: /
EOF&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="section" id="apache-configuration"&gt;
&lt;h3&gt;10.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Apache configuration&lt;/h3&gt;
&lt;p&gt;Edit the default site configuration file
&lt;em&gt;/etc/apache2/sites-enabled/000-default.conf&lt;/em&gt; and make it look like something
like below:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
&amp;lt;VirtualHost *:80&amp;gt;
  ServerName maps.example.org
  ServerAdmin webmaster&amp;#64;example.org
  DocumentRoot /var/www/html

  ErrorLog ${APACHE_LOG_DIR}/error.log
  CustomLog ${APACHE_LOG_DIR}/access.log combined

  &amp;lt;Directory &amp;quot;/var/www/html/nominatim&amp;quot;&amp;gt;
    Options FollowSymLinks MultiViews
    AddType text/html .php
  &amp;lt;/Directory&amp;gt;
&amp;lt;/VirtualHost&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Apply changes by restarting web server:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
apache2ctl&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="install-the-nominatim-web-site"&gt;
&lt;h3&gt;10.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Install the Nominatim Web Site&lt;/h3&gt;
&lt;p&gt;The installation should be done as the nominatim user:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
su&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;nominatim&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Nominatim
&lt;/pre&gt;
&lt;p&gt;Run the setup.php with the option to create the web site:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
./utils/setup.php&lt;span class="w"&gt; &lt;/span&gt;--create-website&lt;span class="w"&gt; &lt;/span&gt;/var/www/html/nominatim
&lt;/pre&gt;
&lt;p&gt;At this point, the site is ready and you can point your browser to the base URL
and try it out. It should look something like this:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/Valinta_064.png"&gt;&lt;img alt="Valinta_064" class="alignnone size-full wp-image-1104" src="https://mikko.kortelainen.io/blog/files/Valinta_064.png" style="width: 543px; height: 387px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="enable-osm-updates"&gt;
&lt;h2&gt;11&amp;nbsp;&amp;nbsp;&amp;nbsp;Enable OSM Updates&lt;/h2&gt;
&lt;p&gt;We will configure a cron job to have the database updated periodically using
diffs from Geofabrik.de. As the nominatim user:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;settings/configuration.txt&lt;span class="w"&gt;
&lt;/span&gt;./utils/setup.php&lt;span class="w"&gt; &lt;/span&gt;--osmosis-init
&lt;/pre&gt;
&lt;p&gt;Enable hierarchical updates in the database (these were off during import to
speed things up):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
./utils/setup.php&lt;span class="w"&gt; &lt;/span&gt;--create-functions&lt;span class="w"&gt; &lt;/span&gt;--enable-diff-updates
&lt;/pre&gt;
&lt;p&gt;Run once to get up to date:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
./utils/update.php&lt;span class="w"&gt; &lt;/span&gt;--import-osmosis&lt;span class="w"&gt; &lt;/span&gt;--no-npi
&lt;/pre&gt;
&lt;p&gt;There seems to be a time check in the import function that prevents another run
immediately. Instead it will wait until the interval configured in the
&amp;quot;Configure Local Settings&amp;quot; section earlier in this post has passed (default is 1
day).&lt;/p&gt;
&lt;p&gt;We will add the command to crontab to be executed every monday at 03:00. Run:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
crontab&lt;span class="w"&gt; &lt;/span&gt;-e
&lt;/pre&gt;
&lt;p&gt;Add a new line to the crontab file looking like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
00 03 * * mon /home/nominatim/Nominatim/utils/update.php --import-osmosis --no-npi &amp;gt;&amp;gt;/home/nominatim/nominatim-update.log 2&amp;gt;&amp;amp;1
&lt;/pre&gt;
&lt;p&gt;A log file will be created as &lt;em&gt;/home/nominatim/nominatim-update.log&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wrap-up"&gt;
&lt;h2&gt;12&amp;nbsp;&amp;nbsp;&amp;nbsp;Wrap Up&lt;/h2&gt;
&lt;p&gt;That's it! You can get JSON or XML data out of the database with http requests.
A couple of examples:&lt;/p&gt;
&lt;p&gt;Forward geocoding:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://maps.example.org/nominatim/search.php?format=jsonv2&amp;amp;q=mannerheimintie"&gt;http://maps.example.org/nominatim/search.php?format=jsonv2&amp;amp;q=mannerheimintie&lt;/a&gt;, helsinki&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Reverse geocoding:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://maps.example.org/nominatim/reverse.php?format=jsonv2&amp;amp;lat=60.1805&amp;amp;lon=24.9434"&gt;http://maps.example.org/nominatim/reverse.php?format=jsonv2&amp;amp;lat=60.1805&amp;amp;lon=24.9434&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Check out the &lt;a class="reference external" href="http://wiki.openstreetmap.org/wiki/Nominatim"&gt;Nominatim documentation&lt;/a&gt; for details.&lt;/p&gt;
&lt;p&gt;This post was adapted from my notes of such an installation process. Let me know
in the comments section if I introduced any mistakes. Other comments are also
welcome!&lt;/p&gt;
&lt;div class="section" id="useful-links"&gt;
&lt;h3&gt;12.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Useful links&lt;/h3&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.openstreetmap.org"&gt;http://www.openstreetmap.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://nominatim.openstreetmap.org/"&gt;http://nominatim.openstreetmap.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.openstreetmap.org/wiki/Nominatim"&gt;http://wiki.openstreetmap.org/wiki/Nominatim&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.openstreetmap.org/wiki/Nominatim/Installation"&gt;http://wiki.openstreetmap.org/wiki/Nominatim/Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/cyclestreets/nominatim-install"&gt;https://github.com/cyclestreets/nominatim-install&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Apache"></category><category term="Geoinformatics"></category><category term="Nominatim"></category><category term="OpenStreetMap"></category><category term="PostGIS"></category><category term="PostgreSQL"></category><category term="Ubuntu"></category></entry><entry><title>Remove Unwanted Files From Git History</title><link href="https://mikko.kortelainen.io/blog/remove-unwanted-files-from-git-history/" rel="alternate"></link><published>2014-12-18T13:06:00+02:00</published><updated>2014-12-18T13:06:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2014-12-18:/blog/remove-unwanted-files-from-git-history/</id><summary type="html">&lt;p&gt;Here's an example of how to remove every *.pyc file from every commit in Git
history. It is adapted from
&lt;a class="reference external" href="https://help.github.com/articles/remove-sensitive-data/"&gt;this Git help page&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="rewrite-history"&gt;
&lt;h2&gt;Rewrite history&lt;/h2&gt;
&lt;p&gt;Run &lt;tt class="docutils literal"&gt;git &lt;span class="pre"&gt;filter-branch&lt;/span&gt;&lt;/tt&gt;, forcing (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--force&lt;/span&gt;&lt;/tt&gt;) Git to process—but not check
out (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--index-filter&lt;/span&gt;&lt;/tt&gt;)—the entire history of every branch and tag
(&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--tag-name-filter&lt;/span&gt; cat &lt;span class="pre"&gt;--&lt;/span&gt; &lt;span class="pre"&gt;--all …&lt;/span&gt;&lt;/tt&gt;&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Here's an example of how to remove every *.pyc file from every commit in Git
history. It is adapted from
&lt;a class="reference external" href="https://help.github.com/articles/remove-sensitive-data/"&gt;this Git help page&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="rewrite-history"&gt;
&lt;h2&gt;Rewrite history&lt;/h2&gt;
&lt;p&gt;Run &lt;tt class="docutils literal"&gt;git &lt;span class="pre"&gt;filter-branch&lt;/span&gt;&lt;/tt&gt;, forcing (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--force&lt;/span&gt;&lt;/tt&gt;) Git to process—but not check
out (&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--index-filter&lt;/span&gt;&lt;/tt&gt;)—the entire history of every branch and tag
(&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--tag-name-filter&lt;/span&gt; cat &lt;span class="pre"&gt;--&lt;/span&gt; &lt;span class="pre"&gt;--all&lt;/span&gt;&lt;/tt&gt;), removing the specified files (&lt;tt class="docutils literal"&gt;'git rm
&lt;span class="pre"&gt;--cached&lt;/span&gt; &lt;span class="pre"&gt;--ignore-unmatch&lt;/span&gt; *.pyc'&lt;/tt&gt;) and any empty commits generated as a result
(&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--prune-empty&lt;/span&gt;&lt;/tt&gt;).&lt;/p&gt;
&lt;p&gt;Be careful! This will overwrite your existing tags.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;filter-branch&lt;span class="w"&gt; &lt;/span&gt;--force&lt;span class="w"&gt; &lt;/span&gt;--index-filter&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="s1"&gt;'git rm --cached --ignore-unmatch *.pyc'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;--prune-empty&lt;span class="w"&gt; &lt;/span&gt;--tag-name-filter&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;--&lt;span class="w"&gt; &lt;/span&gt;--all&lt;span class="w"&gt;

&lt;/span&gt;Ref&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'refs/heads/master'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;was&lt;span class="w"&gt; &lt;/span&gt;rewritten&lt;span class="w"&gt;
&lt;/span&gt;Ref&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'refs/remotes/origin/master'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;was&lt;span class="w"&gt; &lt;/span&gt;rewritten&lt;span class="w"&gt;
&lt;/span&gt;WARNING:&lt;span class="w"&gt; &lt;/span&gt;Ref&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'refs/remotes/origin/master'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;unchanged
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="add-a-gitignore-entry"&gt;
&lt;h2&gt;Add a .gitignore entry&lt;/h2&gt;
&lt;p&gt;This is to prevent you from committing the files again.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'*.pyc'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;.gitignore&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;.gitignore&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Ignore .pyc files'&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="force-push-to-remote"&gt;
&lt;h2&gt;Force-push to remote&lt;/h2&gt;
&lt;p&gt;If you have a remote repository, the push must be forced so that all remote
branches and tags and rewritten.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;--force&lt;span class="w"&gt; &lt;/span&gt;--all&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;origin&lt;span class="w"&gt; &lt;/span&gt;--force&lt;span class="w"&gt; &lt;/span&gt;--tags
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="fix-every-copy-of-the-repository"&gt;
&lt;h2&gt;Fix every copy of the repository&lt;/h2&gt;
&lt;p&gt;You can delete and re-clone every copy of the repository, or rebase, or delete
every affected branch and re-create them.&lt;/p&gt;
&lt;p&gt;For example to rebase:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;fetch&lt;span class="w"&gt; &lt;/span&gt;--all&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;lastest-commit-id&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Git"></category></entry><entry><title>Adding Git version control to web sites</title><link href="https://mikko.kortelainen.io/blog/adding-git-version-control-to-web-sites/" rel="alternate"></link><published>2014-08-13T16:20:00+03:00</published><updated>2014-08-13T16:20:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2014-08-13:/blog/adding-git-version-control-to-web-sites/</id><summary type="html">&lt;p&gt;Here's a little script I made to make it easy&amp;nbsp;to put&amp;nbsp;a number of&amp;nbsp;existing web sites residing&amp;nbsp;under &lt;em&gt;/var/www&lt;/em&gt;&amp;nbsp;under version control by Git. Regarding&amp;nbsp;security, it is&amp;nbsp;obviously&amp;nbsp;not a good idea to initialize the Git repository directly under the site directory, since from there it …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's a little script I made to make it easy&amp;nbsp;to put&amp;nbsp;a number of&amp;nbsp;existing web sites residing&amp;nbsp;under &lt;em&gt;/var/www&lt;/em&gt;&amp;nbsp;under version control by Git. Regarding&amp;nbsp;security, it is&amp;nbsp;obviously&amp;nbsp;not a good idea to initialize the Git repository directly under the site directory, since from there it might be served by the web server to the outside world. And that is not what I&amp;nbsp;want. Instead what I want is to have the Git working directory directly in the site directory that is served, and the repository somewhere else. That is perfectly possible with Git, just by setting one or two environment variables.&lt;/p&gt;
&lt;p&gt;What this script does is actually create an interactive subshell for working with the separated working directory and repository. &amp;nbsp;The environment is initialized automatically, the umask is set correctly, and the prompt is changed to remind&amp;nbsp;the user she is working inside this particular site's environment.&amp;nbsp;You can deploy it many times for multiple sites, customize it for each site, and keep all the repositories under one root directory, each in their own subdirectory. You don't have to remember any of this, just the name of the site or script. You are ready to work with the site once you simply run the script. Pull from a remote, make changes, commit, push, whatever you want. When you are finished, just type 'exit' to&amp;nbsp;get out of the site's environment. &amp;nbsp;You can then run another script to work on another site.&lt;/p&gt;
&lt;p&gt;So for example, if you have two sites, called &lt;em&gt;first.example.org&lt;/em&gt; and &lt;em&gt;second.example.org&lt;/em&gt;, save two copies of the script on your server under &lt;em&gt;/usr/local/bin&lt;/em&gt; or &lt;em&gt;$HOME/bin&lt;/em&gt;. The name of the first copy could be &lt;em&gt;first.example.org&lt;/em&gt; and the name of the second copy could be &lt;em&gt;second.example.org&lt;/em&gt;. Edit both files and set the WORKROOT variable to where your sites are situated (eg. &lt;em&gt;/var/www&lt;/em&gt;) and REPOROOT to where you want your repositories to go. These paths can be the same in both files. What must be different is the WORKNAME variable, which should be the name of the directory under which the particular site is. The variables&amp;nbsp;should look something like this:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;/usr/local/bin/first.example.org&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;WORKNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;first.example.org&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;WORKROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/www&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;REPOROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/git/www/repos&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;*&amp;nbsp;/usr/local/bin/second.example.org*:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
WORKNAME=&amp;quot;second.example.org&amp;quot;
WORKROOT=&amp;quot;/var/www&amp;quot;
REPOROOT=&amp;quot;/var/git/www/repos&amp;quot;
&lt;/pre&gt;
&lt;p&gt;This configuration means your site roots are:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;/var/www/first.example.org&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;/var/www/second.example.org&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those will be used as the Git working directories.&amp;nbsp;The&amp;nbsp;corresponding&amp;nbsp;repositories will be:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;/var/git/www/repos/first.example.org&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;/var/git/www/repos/second.example.org&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But you don't really have to remember that because all you need to do is run either of the scripts and just use git as you are used to. When you're done, type 'exit' or hit Ctrl+D and you can run another script to get to another site's environment.&lt;/p&gt;
&lt;p&gt;Give yourself permission to execute the script files under &lt;em&gt;/usr/local/bin&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here's what an example first run looks like. First create&amp;nbsp;the repository root directory and set suitable permissions (assuming you belong to the &lt;em&gt;admin&lt;/em&gt; group):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;/var/git&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;chgrp&lt;span class="w"&gt; &lt;/span&gt;admin&lt;span class="w"&gt; &lt;/span&gt;/var/git&lt;span class="w"&gt;
&lt;/span&gt;$&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;g+w&lt;span class="w"&gt; &lt;/span&gt;/var/git
&lt;/pre&gt;
&lt;p&gt;Then run the first script:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;first.example.org&lt;span class="w"&gt;
&lt;/span&gt;Entering&lt;span class="w"&gt; &lt;/span&gt;shell&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;environment&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;first.example.org&lt;span class="w"&gt;
&lt;/span&gt;Git&lt;span class="w"&gt; &lt;/span&gt;repository&lt;span class="w"&gt; &lt;/span&gt;is:&lt;span class="w"&gt; &lt;/span&gt;/var/git/www/repos/first.example.org&lt;span class="w"&gt;
&lt;/span&gt;fatal:&lt;span class="w"&gt; &lt;/span&gt;Not&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;git&lt;span class="w"&gt; &lt;/span&gt;repository:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'/var/git/www/repos/first.example.org'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;Initialize&lt;span class="w"&gt; &lt;/span&gt;repository&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'git init'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt;
&lt;/span&gt;Type&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'exit'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;out&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;environment
&lt;/pre&gt;
&lt;p&gt;As you can see, there is no Git repository yet. That has to be initialized and a first commit made.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
$ git init
Initialized empty Git repository in /var/git/www/repos/first.example.org/
$ git add .
$ git commit -m 'First commit'
[master (root-commit) 03de73b] First commit
 1 file changed, 3 insertions(+)
 create mode 100644 index.html
$ exit
&lt;/pre&gt;
&lt;p&gt;As you can see, this is just typical Git usage. You can configure remotes, push and pull, make changes and commit them.&lt;/p&gt;
&lt;p&gt;The second time you enter the site's environment by running the script, the welcome message will look a bit different.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
$&lt;span class="w"&gt; &lt;/span&gt;first.example.org&lt;span class="w"&gt;
&lt;/span&gt;Entering&lt;span class="w"&gt; &lt;/span&gt;shell&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;environment&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;first.example.org&lt;span class="w"&gt;
&lt;/span&gt;Git&lt;span class="w"&gt; &lt;/span&gt;repository&lt;span class="w"&gt; &lt;/span&gt;is:&lt;span class="w"&gt; &lt;/span&gt;/var/git/www/repos/first.example.org&lt;span class="w"&gt;
&lt;/span&gt;On&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;master&lt;span class="w"&gt;
&lt;/span&gt;nothing&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;commit,&lt;span class="w"&gt; &lt;/span&gt;working&lt;span class="w"&gt; &lt;/span&gt;directory&lt;span class="w"&gt; &lt;/span&gt;clean&lt;span class="w"&gt;
&lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;master&lt;span class="w"&gt; &lt;/span&gt;03de73b&lt;span class="w"&gt; &lt;/span&gt;First&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt;
&lt;/span&gt;Type&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'exit'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;get&lt;span class="w"&gt; &lt;/span&gt;out&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;environment
&lt;/pre&gt;
&lt;p&gt;After running the &lt;em&gt;second.example.org&lt;/em&gt; script you can go and initialize the repository for the second&amp;nbsp;site as well. It is just the same as the first one.&lt;/p&gt;
&lt;p&gt;Below is the script. Just save it, and customize&amp;nbsp;the WORKROOT and REPOROOT variables how you like them. Then make as many copies of the script as you have sites, and customize the WORKNAME variable to match each site. Add execute permissions.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="ch"&gt;#!/bin/bash
&lt;/span&gt;&lt;span class="c1"&gt;#
# This script starts a new interactive shell with GIT_DIR and GIT_WORK_TREE
# set to different locations. You can use git normally, but the .git/
# directory contents will be kept in a different location and not under the
# working directory.
#
# You can customize the three variables below to reflect the locations of
# the the repository and the working tree:
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;WORKNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;first.example.org&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;WORKROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/www&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;REPOROOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/git/www/repos&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# The $WORKNAME is the name of the working directory. It will also be used
# as the name of the directory for the bare repository.
#
# The $WORKROOT is the root directory under which the working directory is
# situated (meaning the checked out files).
#
# The $REPOROOT is the root directory under which the bare repository is
# situated (meaning all the stuff usually under .git/)
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# If set, the umask will be set to this. We want to give full privileges
# to the group.
&lt;/span&gt;&lt;span class="nv"&gt;SETUMASK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0002&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Put the commands you want to execute inside the new shell before going
# into interactive mode between the two EOF:s below. They will be read
# into the variable $RCFILE and will be executed after the shell has been
# started.
&lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-r&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;RCFILE&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt;'EOF'

# First read the regular bashrc file
source $HOME/.bashrc;

# Then change the prompt to reflect the fact we are in a new environment
export PS1=&amp;quot;\n\t ($WORKNAME) \u&amp;#64;\h:\n\w\a\\$ &amp;quot;;

# Display status of current repository
git status &amp;amp;&amp;amp; git branch -av || echo &amp;quot;Initialize repository with 'git init' and commit&amp;quot;

echo &amp;quot;Type 'exit' to get out of the environment&amp;quot;

EOF&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# This is used in the $RCFILE
&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;WORKNAME&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# === Probably no need to touch stuff below this point ===
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Entering shell with environment for &lt;/span&gt;&lt;span class="nv"&gt;$WORKNAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;GIT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$REPOROOT&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$WORKNAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;GIT_WORK_TREE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$WORKROOT&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;$WORKNAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Git repository is: &lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Set umask if variable is set
&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-z&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$SETUMASK&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;umask&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$SETUMASK&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Create directories if they do not exist already
&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-e&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$GIT_WORK_TREE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$GIT_WORK_TREE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$GIT_WORK_TREE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Start a new interactive shell and keep it running until &amp;quot;exit&amp;quot;
&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-z&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$RCFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;--rcfile&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$RCFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It is quite straightforward. First the configuration variables are defined, as well as the RCFILE variable which is read from a here document. Next the important Git variables GIT_DIR and GIT_WORK_TREE are exported. After possibly creating directories, another bash is executed in interactived mode, and the RCFILE variable is fed to it as the rc file to be executed at the start of the shell. So in reality&amp;nbsp;the user will be working in a sub-subshell until she exits.&lt;/p&gt;
</content><category term="Blog"></category><category term="Git"></category><category term="Shell scripts"></category></entry><entry><title>Upsert Methods for PostgreSQL</title><link href="https://mikko.kortelainen.io/blog/upsert-methods-for-postgresql/" rel="alternate"></link><published>2014-01-04T15:31:00+02:00</published><updated>2014-01-04T15:31:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2014-01-04:/blog/upsert-methods-for-postgresql/</id><summary type="html">&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;em&gt;: PostgreSQL 9.5&lt;/em&gt; &lt;a class="reference external" href="https://wiki.postgresql.org/wiki/What's_new_in_PostgreSQL_9.5#INSERT_..._ON_CONFLICT_DO_NOTHING.2FUPDATE_.28.22UPSERT.22.29"&gt;has been released with INSERT .. ON CONFLICT UPDATE support&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;PostgreSQL has no &amp;quot;upsert&amp;quot; or &amp;quot;replace&amp;quot; or &amp;quot;insert .. on duplicate key update&amp;quot; or &amp;quot;merge into&amp;quot; construct to conditionally either insert a new row, or if a row with the key already exists, to either update the existing …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;&lt;em&gt;: PostgreSQL 9.5&lt;/em&gt; &lt;a class="reference external" href="https://wiki.postgresql.org/wiki/What's_new_in_PostgreSQL_9.5#INSERT_..._ON_CONFLICT_DO_NOTHING.2FUPDATE_.28.22UPSERT.22.29"&gt;has been released with INSERT .. ON CONFLICT UPDATE support&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;PostgreSQL has no &amp;quot;upsert&amp;quot; or &amp;quot;replace&amp;quot; or &amp;quot;insert .. on duplicate key update&amp;quot; or &amp;quot;merge into&amp;quot; construct to conditionally either insert a new row, or if a row with the key already exists, to either update the existing row with the new values, or first delete the old row and then insert a new one. This has been discussed many times in the posgresql developers mailing lists, and &lt;a class="reference external" href="http://wiki.postgresql.org/wiki/SQL_MERGE"&gt;plans to implement&lt;/a&gt; the SQL standard &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Merge_%28SQL%29"&gt;MERGE&lt;/a&gt; operation have been devised. But there is still no such functionality in PostgreSQL as of version 9.3. Here are some examples on how to implement the functionality in different ways, using either a &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/upsert-methods-for-postgresql/#function"&gt;function&lt;/a&gt;, a &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/upsert-methods-for-postgresql/#trigger"&gt;trigger&lt;/a&gt; function or a &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/upsert-methods-for-postgresql/#rule"&gt;rule&lt;/a&gt;. None of them are perfect. There are trade-offs to be made.&lt;/p&gt;
&lt;p&gt;To implement similar functionality, there are a couple of ways. One is to first explicitly check if a row already exists, and then, depending on which semantics, merge or replace, you want, issue either INSERT or UPDATE query (for merge), or either INSERT or DELETE/INSERT queries (for replace).&lt;/p&gt;
&lt;p&gt;Another way is to first try to INSERT the new value, and then check if an exception is raised. If not, the insert worked. If an exception is raised, the row exists and must be either UPDATEd (for merge) or DELETEd and a new one INSERTed (for replace).&lt;/p&gt;
&lt;p&gt;Doing it for one row is fine, but if you need to do it for thousands of rows in one shot, you will run into either your whole transaction aborting after the first duplicate key violation, or the fact that you must issue selects and inserts/updates/deletes according to application logic over the network for each row. And doing each operation in a separate transaction will be slow. Also, having multiple database sessions doing merges on a table simultaneously may result in problems.&lt;/p&gt;
&lt;p&gt;For a very good in-depth discussion on the topic, see this article: &lt;a class="reference external" href="http://www.depesz.com/2012/06/10/why-is-upsert-so-complicated/"&gt;Why is UPSERT so complicated?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here's an example table we'll be working on:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Let's start merging values. The first two methods need application logic every step of the way to work.&lt;/p&gt;
&lt;div class="section" id="using-select"&gt;
&lt;h2&gt;Using SELECT&lt;/h2&gt;
&lt;p&gt;Conceptually it looks like this:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- If found:
&lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- Else:
&lt;/span&gt;&lt;span class="n"&gt;INSERTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- End if.
&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- If found:
&lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- Else:
&lt;/span&gt;&lt;span class="n"&gt;INSERTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- End if.
&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here, the application must check after each SELECT if the row exists, and issue either an UPDATE or an INSERT. That means a lot of traffic between client and server.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="using-savepoints"&gt;
&lt;h2&gt;Using Savepoints&lt;/h2&gt;
&lt;p&gt;Conceptually it looks like this:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;SAVEPOINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- If exception:
&lt;/span&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SAVEPOINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- end exception.
&lt;/span&gt;&lt;span class="k"&gt;SAVEPOINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- If exception:
&lt;/span&gt;&lt;span class="k"&gt;ROLLBACK&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SAVEPOINT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;-- end exception.
&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Your code will have to do the exception checking after each INSERT and roll back to the previous savepoint. And your application must do the checking every step of the way.&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="using-a-function"&gt;
&lt;h2&gt;Using a Function&lt;/h2&gt;
&lt;p&gt;We can move the checking part of the job to the database server, reducing the needed network round-trips between the database server and the application.&lt;/p&gt;
&lt;p&gt;This function will first try to insert, and failing that, will update an existing row. You can use this without fearing that your transaction gets aborted due to unique constraint violations on the way.&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merge_test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;the_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VOID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;the_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;EXCEPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unique_violation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LANGUAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This makes it possible to issue all the queries in one shot to the server, without needing to use application logic between the queries.&lt;/p&gt;
&lt;p&gt;Merge some rows:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merge_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merge_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;COMMIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Or even simply:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merge_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;merge_test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This works if you are content with the possibility that some other transaction might delete the row you have just merged before your transaction returns and you think you have an existing row in the database. If you know nobody does deletes on the table, you're fine. Another version which loops until a row exists and is up-to-date can work better. This one is adapted straight from the &lt;a class="reference external" href="http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-UPSERT-EXAMPLE"&gt;PostgreSQL documentation&lt;/a&gt;:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loop_merge_test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;the_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VOID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;LOOP&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;FOUND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;-- Not found, try insert and check exceptions in case someone inserted
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;-- the same key concurrently as we speak
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INTO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;VALUES&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;the_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the_value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;EXCEPTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHEN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;unique_violation&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="c1"&gt;-- do nothing; just loop back to the UPDATE
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LOOP&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LANGUAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;This one will loop until it succeeds in either operation. Using this you can be a bit more sure that after running the merge a row will exist in the table. But, with this one, if there are other unique constraints on the table, we might be in trouble because we did not check which column generated the unique violation. See the &lt;a class="reference external" href="http://www.postgresql.org/docs/current/static/plpgsql-control-structures.html#PLPGSQL-ERROR-TRAPPING"&gt;documentation&lt;/a&gt; for a discussion on this.&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="using-a-trigger"&gt;
&lt;h2&gt;Using a Trigger&lt;/h2&gt;
&lt;p&gt;If the semantics regarding your particular table are such that insert operations should never fail, but should always work as merge operations instead, you can write a trigger function to do it. Let's make a second table for this test first with:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Then the trigger:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FUNCTION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;before_insert_test2&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RETURNS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRIGGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;BEGIN&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;THEN&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;-- found; update, and return null to prevent the insert
&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IF&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;-- not found; just return row to insert
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;RETURN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;END&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="dl"&gt;&lt;/span&gt;&lt;span class="s"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;LANGUAGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;plpgsql&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TRIGGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2_merge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BEFORE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FOR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EACH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROW&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;EXECUTE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PROCEDURE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;before_insert_test2&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;There's a caveat, though. If the id you are inserting already exists, your insert operation will return with an inserted row count of 0. That is kind of both correct and incorrect. Correct when you think of it in insert terms, but incorrect when you think of it in merge terms. Just don't test your success by looking at the row count.&lt;/p&gt;
&lt;pre class="code psql literal-block"&gt;
&lt;span class="gp"&gt;test=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;INSERT 0 1
&lt;/span&gt;&lt;span class="gp"&gt;test=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;INSERT 0 0&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You can also write your merge operation into one insert query:&lt;/p&gt;
&lt;pre class="code psql literal-block"&gt;
&lt;span class="gp"&gt;test=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'d'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'e'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;INSERT 0 4&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;So now one row was updated and four were inserted. And all the dirty stuff is handled server side.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;But this approach has the possibility of running into an exception if there are multiple sessions working concurrently with the data. So you must re-try the whole operation if it fails.&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="using-a-rule"&gt;
&lt;h2&gt;Using a Rule&lt;/h2&gt;
&lt;p&gt;Similar functionality as described above using a trigger can be written using the rule system. Let's make a third test table:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INTEGER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;PRIMARY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This rule will test whether a row with the given id exists, and if it does, it will issue an update query instead:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OR&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;REPLACE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;RULE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test3_merge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSERT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test3&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;EXISTS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;DO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;INSTEAD&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;UPDATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NEW&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This has the same caveat regarding the reported row count as the trigger way. Your row count will be incremented by 0 if the row already existed and was merely updated.&lt;/p&gt;
&lt;pre class="code psql literal-block"&gt;
&lt;span class="gp"&gt;test=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;INSERT 0 1
&lt;/span&gt;&lt;span class="gp"&gt;test=#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'A'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'B'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'c'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="go"&gt;INSERT 0 2&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;There is an extra SELECT query here, but the PostgreSQL rule system is clever, so it will actually only issue one INSERT operation and one UPDATE operation on the table for the whole data (use EXPLAIN to see the query plan yourself). Triggers are always fired for every row, so they are slower than rules.&lt;/p&gt;
&lt;p&gt;The rule method seems like the fastest way of doing this particular merge. Not by any measured benchmark, but just my personal gut feeling. But this method has the possibility of exceptions in concurrent situations, so you must be ready to handle them in your application code, and re-try when needed.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="PostgreSQL"></category></entry><entry><title>SQLAlchemy Declarative Class Reflector</title><link href="https://mikko.kortelainen.io/blog/sqlalchemy-declarative-class-reflector/" rel="alternate"></link><published>2013-12-20T17:40:00+02:00</published><updated>2013-12-20T17:40:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-12-20:/blog/sqlalchemy-declarative-class-reflector/</id><summary type="html">&lt;p&gt;SQLAlchemy has a nice reflection facility which takes for example a database
table name as argument and produces a &lt;em&gt;Table&lt;/em&gt; object out of it for manipulation.
However, those objects do not behave like the objects produced by declarative
classes, which are easier to work with. Here's a little class that …&lt;/p&gt;</summary><content type="html">&lt;p&gt;SQLAlchemy has a nice reflection facility which takes for example a database
table name as argument and produces a &lt;em&gt;Table&lt;/em&gt; object out of it for manipulation.
However, those objects do not behave like the objects produced by declarative
classes, which are easier to work with. Here's a little class that helps to
bridge that gap by reflecting proper declarative classes from database tables.
It has only been tested with PostgreSQL, but it may work with other databases as
well.&lt;/p&gt;
&lt;p&gt;The class &lt;em&gt;SQLReflector&lt;/em&gt; requires the preconfigured SQLAlchemy database engine
as argument. Example (try in IPython):&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="c1"&gt;# Make a connection string&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;getpass&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getpass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;connstr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;postgresql+psycopg2://username:&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;#64;localhost/dbname&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Create an engine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_engine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connstr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Create the SQLReflector object using the engine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlreflector&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SQLReflector&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;reflector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SQLReflector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Start a session (you can use sqlreflector.session as well)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;sessionmaker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The instantiated &lt;em&gt;SQLReflector&lt;/em&gt; object can be used to reflect database objects
using the following methods:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;reflect_table(schema_name, table_name)&lt;/strong&gt;: reflects a single table into a class&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;reflect_tables(schema_name, table_name_list)&lt;/strong&gt;: reflects multiple tables at once from one schema&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;reflect_schema(schema_name)&lt;/strong&gt;: reflects all tables and sequences in the given schema&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;reflect_database()&lt;/strong&gt;: reflects everything from a database&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So to reflect the table &amp;quot;my_table&amp;quot; in schema &amp;quot;public&amp;quot;, write:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;MyTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reflector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflect_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;public&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;my_table&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now you can query it like any declarative class:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;myrow&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyTable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyTable&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The &lt;strong&gt;reflect_table&lt;/strong&gt; method accepts a &lt;em&gt;column_definitions&lt;/em&gt; argument. You can
use that to define missing stuff, such as primary keys for views, or foreign key
relationships not defined in the database.&lt;/p&gt;
&lt;p&gt;For example PostgreSQL views don't have primary keys, which causes problems with
SQLAlchemy. To define a primary key while reflecting the class, you can write
something like this:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;MyView&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reflector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflect_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="s1"&gt;'my_schema'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="s1"&gt;'my_view'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="n"&gt;column_definitions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                  &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id_col'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;          &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;To define an explicit foreign key, you can write something like:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;MyTable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reflector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflect_class&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="s1"&gt;'my_schema'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="s1"&gt;'my_table'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="n"&gt;column_definitions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                  &lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                      &lt;span class="s1"&gt;'fk_col'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                      &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                      &lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'foreign_schema.foreign_table.foreign_column'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                  &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;              &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;          &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You can find all the tables you have reflected in the &lt;em&gt;SQLReflector&lt;/em&gt; instance,
under the &lt;em&gt;classes&lt;/em&gt; property. Every schema you have used is there, and under
each schema every table you have reflected. So if you
run&amp;nbsp;&lt;strong&gt;reflector.reflect_database()&lt;/strong&gt;, you should find all you schemas under
&lt;em&gt;reflector.classes&lt;/em&gt;, and every table like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;reflector.classes.&amp;lt;schema_name&amp;gt;.&amp;lt;class_name&amp;gt;&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;But remember, if you have any views defined in a PostgreSQL database, the
&lt;strong&gt;reflect_database()&lt;/strong&gt; call will fail, because you must explicitly add a primary
key constraint to every view to please SQLAlchemy.&lt;/p&gt;
&lt;p&gt;There are a couple of helper methods to snoop around the database and see what's
there. The method &lt;strong&gt;get_schema_names()&lt;/strong&gt; will give a list of schema names in the
database. The method &lt;strong&gt;get_table_names(schema_name)&lt;/strong&gt; will give a list of table
names in a given schema. There is a full sqlalchemy.engine.reflection.Inspector
object in the instantiated SQLReflector object (the class member name is, not
surprisingly, &amp;quot;inspector&amp;quot;). You can use that to further inspect the database.&lt;/p&gt;
&lt;p&gt;SQL objects can have names containing for example accented letters and special
characters. Python 2 allows only letters, numbers and underscores in identifier
names. Python 3 allows some unicode characters in identifiers. For
compatibility's sake, SQLReflector mangles SQL identifiers so that the resulting
Python identifiers contain only letters, numbers and underscores.&lt;/p&gt;
&lt;p&gt;By default, table names are converted into CamelCase in such a way, that the
name is converted into lowercase, and after that, underscore characters in table
names are removed, and the character following the underscore character is
changed into uppercase. Also first character is uppercased.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Table called &amp;quot;my_data&amp;quot; becomes a class called &amp;quot;MyData&amp;quot;&lt;/li&gt;
&lt;li&gt;Table called &amp;quot;MyData&amp;quot; becomes a class called &amp;quot;Mydata&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don't like this behaviour, you can disable it by giving a
&amp;quot;camelcase=False&amp;quot; argument to the constructor. In this case, the schema name
sanitizer is used for table names.&lt;/p&gt;
&lt;p&gt;Schema names are not converted into CamelCase, but are sanitized from unwanted
characters.&lt;/p&gt;
&lt;p&gt;You can disable all sanitization by giving the class constructor a
&amp;quot;sanitize_names=False&amp;quot; argument. In this case the SQL name is used as the class
name whatever it is, possibly resulting in exceptions if the class name contains
characters Python does not accept.&lt;/p&gt;
&lt;p&gt;Here's the code (&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/files/sqlreflector.py"&gt;sqlreflector.py&lt;/a&gt;):&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="c1"&gt;# Author Mikko Kortelainen &amp;lt;mikko.kortelainen&amp;#64;techelp.fi&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# Tested (not very thoroughly) with Python 2.7.5 and 3.3.2, and SQLAlchemy 0.8.2&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MetaData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy.orm&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy.ext.declarative&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;declarative_base&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;sqlalchemy.engine&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;reflection&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SQLReflector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Reflects SQLAlchemy declarative classes from database.

    Requires the SQLAlchemy database engine as argument. Tested only with
    PostgreSQL. For example:

    from sqlalchemy import create_engine
    connstr = &amp;quot;postgresql+psycopg2://user:pass&amp;#64;host/database?sslmode=require&amp;quot;
    engine = create_engine(connstr)
    reflector = SQLReflector(engine)
    session = reflector.session

    MyTable = reflector.reflect(&amp;quot;my_schema&amp;quot;, &amp;quot;my_table&amp;quot;)
    a_row = session.query(MyTable).filter(MyTable.id == 1).one()

    After a table has been reflected, it is saved in the SQLReflector object.
    You can find them under the classes property:

    reflector.classes.&amp;lt;schemaname&amp;gt;.&amp;lt;tablename&amp;gt;

    By default schema and table names are sanitized so that characters which
    are not letters, numbers or underscores will be stripped from the name.
    Also, initial numeric characters will be stripped. What's left is treated
    as the identifier. For table names (not schema names), the default is
    also to convert the resulting name into CamelCase by first converting
    it to lowercase and after that removing all underscore characters and
    converting the character following the underscore to uppercase. For
    example:

      Table &amp;quot;my_data&amp;quot; becomes class &amp;quot;MyData&amp;quot;
      Table &amp;quot;MyData&amp;quot; becomes class &amp;quot;Mydata&amp;quot;

    You can turn CamelCase conversion off by giving camelcase=False.

    If you give sanitize_names=False, the names are not sanitized at all
    before making Python identifiers out of them. So your schemas and tables
    should have names that are compliant already.
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;database_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;database_engine&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessionmaker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sessionmaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;MetaData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reflection&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Inspector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_empty_object&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sanitize_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;camelcase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__repr__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Formal representation&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;&amp;lt;SQLReflector sanitize_names=&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt; camelcase=&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="s2"&gt;&amp;quot;True&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sanitize_names&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="s2"&gt;&amp;quot;True&amp;quot;&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;camelcase&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;False&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_schema_names&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Returns a list of available schemas in database&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_schema_names&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_table_names&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Returns a list of available tables in a schema.

        For more in-depth exploration you can use the SQLAlchemy reflection.Inspector
        instance inside the class. The member is called &amp;quot;inspector&amp;quot;. &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_table_names&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reflect_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;column_definitions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; \
                            &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Reflects a table's metadata and creates an SQLAlchemy declarative
        class with a nice sanitized CamelCase name out of it.

        You may give extra column definitions or pretty much anything you want
        to add to the class in the column_definitions argument. For example to
        define an integer primary key to a PostgreSQL view:

        from sqlalchemy import Column, Integer
        MyView  = reflector.reflect_table(
                      'my_schema',
                      'my_view',
                      column_definitions=
                      (
                          Column('id_col', Integer, primary_key=True),
                      )
                  )

        Or you can define an explicit foreign key if such is not in place in the
        database:

        from sqlalchemy import Column, Integer, ForeignKey
        MyTable = reflector.reflect_class(
                      'my_schema',
                      'my_table',
                      column_definitions=
                      (
                          Column(
                              'fk_col',
                              Integer,
                              ForeignKey('foreign_schema.foreign_table.foreign_column')
                          )
                      )
                  )

        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Sanitize names if requested&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;class_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sanitize_tablename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;sane_schema_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sanitize_schemaname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;class_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;sane_schema_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Make a class from declarative_base()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;Base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;declarative_base&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;class_bases&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;column_definitions&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="c1"&gt;# Add extra column_definitions argument as part of the new class&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;table_definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;column_definitions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;autoload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="c1"&gt;# No extra definitions&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;table_definition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="n"&gt;autoload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Make a proper class out of it&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;the_class&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;class_bases&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__table__&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;table_definition&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Save it as self.classes.&amp;lt;sane_schema_name&amp;gt;.&amp;lt;class_name&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sane_schema_name&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sane_schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;make_empty_object&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="nb"&gt;setattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;getattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sane_schema_name&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;class_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;the_class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Also return it&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;the_class&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reflect_tables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_name_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; \
                             &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Makes a list of classes from a list of table names that are all
        defined in the give schema&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflect_table&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; \
                &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;table_name_list&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reflect_schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Reflects all tables in a given schema&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;table_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_table_names&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflect_tables&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;table_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;reflect_database&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Reflects all tables in every schema of the database&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;schema_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inspector&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_schema_names&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;classes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;schema_name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;schema_names&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reflect_schema&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schema_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sanitize_names&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;classes&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;make_empty_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Create an empty object. It is a subclass of object, with the
        distinction, that this one can have its attributes manipulated with
        setattr&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;EmptyObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'EmptyObject'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;EmptyObject&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;underscore_to_camelcase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lower&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capitalize&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="s1"&gt;'_'&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;_&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;capitalize_first_letter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;For Python 2 and 3 compatibility&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'3'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sanitize_tablename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tablename&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Returns a suitable class name derived from tablename
        - accents will be removed from letters
        - other than valid characters will be removed: [^A-Za-z0-9_]
        - underscores will be converted into CamelCase unless camelcase=False
        - initial numeric characters will be stripped
        - first character will be capitalized
        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;unicodedata&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;re&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Substitute accents and convert to ASCII&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;normal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;NFKD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tablename&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ASCII&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ignore&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Remove any unwanted characters&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;new_normal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;[^A-Za-z0-9_]+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Convert underscore_identifiers to CamelCase&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;camel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;underscore_to_camelcase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;new_normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;camel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;new_normal&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Remove initial numeric characters (class names cannot start with a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# number)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;start_alpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^[0-9]+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;camel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Capitalize the first letter (only if CamelCase)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;camelcase&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;classname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;capitalize_first_letter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start_alpha&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="n"&gt;classname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;start_alpha&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;classname&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sanitize_schemaname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;schemaname&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;This sanitizes a schema name so that it can be used as a Python
        object.
        - accents will be removed from letters
        - other than valid characters will be removed: [^A-Za-z0-9_]
        - initial numeric characters will be stripped (must be A-Za-z_)
        &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;unicodedata&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;re&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Substitute accents and convert to ASCII&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;normal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;normalize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;NFKD&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;to_unicode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schemaname&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;ASCII&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ignore&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Remove any unwanted characters&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;new_normal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;[^A-Za-z0-9_]+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="c1"&gt;# Remove initial numeric characters (class names cannot start with a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="c1"&gt;# number)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;        &lt;span class="n"&gt;schema_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;^[0-9]+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_normal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;schema_name&lt;/span&gt;
&lt;/pre&gt;
</content><category term="Blog"></category><category term="PostgreSQL"></category><category term="Python"></category></entry><entry><title>Editing Tabular Data in Vim</title><link href="https://mikko.kortelainen.io/blog/editing-tabular-data-in-vim/" rel="alternate"></link><published>2013-12-20T13:52:00+02:00</published><updated>2013-12-20T13:52:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-12-20:/blog/editing-tabular-data-in-vim/</id><summary type="html">&lt;p&gt;Helpful settings for editing tabular data:&lt;/p&gt;
&lt;pre class="code vim literal-block"&gt;
&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;noexpandtab&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;nowrap&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;tabstop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="nb"&gt;softtabstop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="nb"&gt;shiftwidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Noexpandtab&lt;/em&gt; disables expanding of inputted tabs to spaces. Adjust the number of spaces to your liking. &lt;em&gt;Tabstop&lt;/em&gt; sets the visual appearance of tab stops (here 16 spaces).&lt;/p&gt;
&lt;p&gt;Show tabs visually, disable cursor line …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Helpful settings for editing tabular data:&lt;/p&gt;
&lt;pre class="code vim literal-block"&gt;
&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;noexpandtab&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;nowrap&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;tabstop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="nb"&gt;softtabstop&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt; &lt;span class="nb"&gt;shiftwidth&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;Noexpandtab&lt;/em&gt; disables expanding of inputted tabs to spaces. Adjust the number of spaces to your liking. &lt;em&gt;Tabstop&lt;/em&gt; sets the visual appearance of tab stops (here 16 spaces).&lt;/p&gt;
&lt;p&gt;Show tabs visually, disable cursor line:&lt;/p&gt;
&lt;pre class="code vim literal-block"&gt;
&lt;span class="nb"&gt;syntax&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; Tab &lt;span class="sr"&gt;/\t/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;hi&lt;/span&gt; Tab &lt;span class="k"&gt;gui&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;underline&lt;/span&gt; guifg&lt;span class="p"&gt;=&lt;/span&gt;blue ctermbg&lt;span class="p"&gt;=&lt;/span&gt;blue&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;nocursorline&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Jump one column left or right Ctrl+H / Ctrl+L in both normal and visual modes to make navigation easier:&lt;/p&gt;
&lt;pre class="code vim literal-block"&gt;
nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;L&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Tab&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;H&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; F&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Tab&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;vmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;L&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;f&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Tab&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;vmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;H&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; F&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;Tab&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Jump 10 lines up or down with Ctrl+K / Ctrl+J:&lt;/p&gt;
&lt;pre class="code vim literal-block"&gt;
nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;J&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;j&lt;span class="w"&gt;
&lt;/span&gt;nmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;K&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;k&lt;span class="w"&gt;
&lt;/span&gt;vmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;J&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;j&lt;span class="w"&gt;
&lt;/span&gt;vmap &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;C&lt;span class="p"&gt;-&lt;/span&gt;K&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;k
&lt;/pre&gt;
&lt;p&gt;Disable the behaviour of going to start of line after jumps to make it easier to work on columns:&lt;/p&gt;
&lt;pre class="code vim literal-block"&gt;
&lt;span class="k"&gt;setlocal&lt;/span&gt; &lt;span class="nb"&gt;nosol&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now you can G or gg and have your cursor in the same column where it was. Makes it easy to select, yank, delete and move columns. Just don't add an empty line at the bottom of the file (you can use &amp;quot;set virtualedit=all&amp;quot; to work around that as well if you want).&lt;/p&gt;
&lt;p&gt;Excellent blog post on the subject:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://acg.github.io/2013/03/29/turn-vim-into-excel-tips-for-tabular-data-editing.html"&gt;http://acg.github.io/2013/03/29/turn-vim-into-excel-tips-for-tabular-data-editing.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Blog"></category><category term="Vim"></category></entry><entry><title>Developer Mode for the Samsung Galaxy S4</title><link href="https://mikko.kortelainen.io/blog/developer-mode-for-the-samsung-galaxy-s4/" rel="alternate"></link><published>2013-06-13T11:40:00+03:00</published><updated>2013-06-13T11:40:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-06-13:/blog/developer-mode-for-the-samsung-galaxy-s4/</id><summary type="html">&lt;p&gt;From: &lt;a class="reference external" href="http://forum.radioshack.wdsserve.com/t5/Mobile-Product-Support/Developer-Mode-for-the-Samsung-Galaxy-S4/m-p/109518"&gt;Developer Mode for the Samsung Galaxy S4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Get to the phone's settings by tapping 'menu' from the home screen and then tapping 'settings'&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;tap on 'more'&lt;/li&gt;
&lt;li&gt;tap on 'software information'&lt;/li&gt;
&lt;li&gt;tap on 'About Device'&lt;/li&gt;
&lt;li&gt;find the build number, and tap it 7 times&lt;/li&gt;
&lt;li&gt;on the 7th tap, a prompt …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;From: &lt;a class="reference external" href="http://forum.radioshack.wdsserve.com/t5/Mobile-Product-Support/Developer-Mode-for-the-Samsung-Galaxy-S4/m-p/109518"&gt;Developer Mode for the Samsung Galaxy S4&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Get to the phone's settings by tapping 'menu' from the home screen and then tapping 'settings'&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;tap on 'more'&lt;/li&gt;
&lt;li&gt;tap on 'software information'&lt;/li&gt;
&lt;li&gt;tap on 'About Device'&lt;/li&gt;
&lt;li&gt;find the build number, and tap it 7 times&lt;/li&gt;
&lt;li&gt;on the 7th tap, a prompt should appear alerting you that Developer Options has been unlocked&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You may also wish to:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
android&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;adb&lt;span class="w"&gt;
&lt;/span&gt;adb&lt;span class="w"&gt; &lt;/span&gt;kill-server&lt;span class="w"&gt;
&lt;/span&gt;adb&lt;span class="w"&gt; &lt;/span&gt;start-server
&lt;/pre&gt;
&lt;p&gt;And after that you must accept the USB connection by tapping OK in the prompt on the device after you connect it.&lt;/p&gt;
</content><category term="Blog"></category><category term="Android"></category></entry><entry><title>Set Default search_path for a User in PostgreSQL</title><link href="https://mikko.kortelainen.io/blog/set-default-search_path-for-a-user-in-postgresql/" rel="alternate"></link><published>2013-04-29T14:03:00+03:00</published><updated>2013-04-29T14:03:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-04-29:/blog/set-default-search_path-for-a-user-in-postgresql/</id><content type="html">&lt;p&gt;Here's how to do it:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;ALTER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ROLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myuser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mydb&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;search_path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;myschema&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The same syntax works for any configuration parameter, such as localization parameters.&lt;/p&gt;
</content><category term="Blog"></category><category term="PostgreSQL"></category></entry><entry><title>How to prefer IPv4 over IPv6 for some hosts</title><link href="https://mikko.kortelainen.io/blog/how-to-prefer-ipv4-over-ipv6-for-some-hosts/" rel="alternate"></link><published>2013-04-13T20:06:00+03:00</published><updated>2013-04-13T20:06:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-04-13:/blog/how-to-prefer-ipv4-over-ipv6-for-some-hosts/</id><summary type="html">&lt;p&gt;If an IPv6 address is unreachable, but you can reach the IPv4 one, you can set the preference to IPv4 for that particular address by adding a line such as this in &lt;em&gt;/etc/gai.conf&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
precedence ::ffff:198.145.11.105/128 100
&lt;/pre&gt;
&lt;p&gt;That will set the preference for host …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If an IPv6 address is unreachable, but you can reach the IPv4 one, you can set the preference to IPv4 for that particular address by adding a line such as this in &lt;em&gt;/etc/gai.conf&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
precedence ::ffff:198.145.11.105/128 100
&lt;/pre&gt;
&lt;p&gt;That will set the preference for host 198.145.11.105 to IPv4.&lt;/p&gt;
&lt;p&gt;See &lt;a class="reference external" href="http://linux.die.net/man/5/gai.conf"&gt;gai.conf(5)&lt;/a&gt; for details.&lt;/p&gt;
</content><category term="Blog"></category><category term="IPv6"></category><category term="Linux"></category></entry><entry><title>Linux IPv6 Router: RADVD + DHCPv6</title><link href="https://mikko.kortelainen.io/blog/linux-ipv6-router-radvd-dhcpv6/" rel="alternate"></link><published>2013-03-20T21:04:00+02:00</published><updated>2013-03-20T21:04:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-20:/blog/linux-ipv6-router-radvd-dhcpv6/</id><summary type="html">&lt;p&gt;Unlike IPv4, which uses &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Dhcp"&gt;DHCP&lt;/a&gt; for
configuration, IPv6 uses the &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol"&gt;Neighbor Discovery Protocol&lt;/a&gt; to configure
addresses and gateways. Unfortunately, originally the protocol had no means of
providing addresses of DNS servers to clients, making it necessary to use
&lt;a class="reference external" href="http://en.wikipedia.org/wiki/DHCPv6"&gt;DHCPv6&lt;/a&gt; for that purpose. Modern Linux
and Mac OS X machines are …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Unlike IPv4, which uses &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Dhcp"&gt;DHCP&lt;/a&gt; for
configuration, IPv6 uses the &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol"&gt;Neighbor Discovery Protocol&lt;/a&gt; to configure
addresses and gateways. Unfortunately, originally the protocol had no means of
providing addresses of DNS servers to clients, making it necessary to use
&lt;a class="reference external" href="http://en.wikipedia.org/wiki/DHCPv6"&gt;DHCPv6&lt;/a&gt; for that purpose. Modern Linux
and Mac OS X machines are able to use the
&lt;a class="reference external" href="http://tools.ietf.org/html/rfc6106"&gt;IPv6 Router Advertisement Options for DNS Configuration (RFC 6106)&lt;/a&gt;,
but to my knowledge, Windows clients are not able at the moment. Here's how to
configure a Linux router using &lt;a class="reference external" href="http://www.litech.org/radvd/"&gt;radvd&lt;/a&gt; and the
&lt;a class="reference external" href="http://www.isc.org/software/dhcp"&gt;ISC DHCP daemon&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="network-configuration-and-packet-forwarding"&gt;
&lt;h2&gt;Network Configuration and Packet Forwarding&lt;/h2&gt;
&lt;p&gt;The following configuration has been tested with Ubuntu Server 12.04.2 LTS. For
the purposes of this article, the &lt;em&gt;/etc/network/interfaces&lt;/em&gt; file looks like
this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# eth0 to Internet
iface eth0 inet6 static
  address 2001:db8:0:1::2
  netmask 64
  gateway 2001:db8:0:1::1

# eth1 to internal network
iface eth1 inet6 static
  address 2001:db8:0:2::1
  netmask 64
&lt;/pre&gt;
&lt;p&gt;Outbound interface is &lt;em&gt;eth0&lt;/em&gt;, and inbound interface &lt;em&gt;eth1&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;First, to enable IPv6 packet forwarding, put this in your &lt;em&gt;/etc/sysctl.conf&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
net.ipv6.conf.all.forwarding=1
&lt;/pre&gt;
&lt;p&gt;And run this to make the change in the running kernel:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;sysctl&lt;span class="w"&gt; &lt;/span&gt;-w&lt;span class="w"&gt; &lt;/span&gt;net.ipv6.conf.all.forwarding&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="ipv6-router-advertisement-daemon"&gt;
&lt;h2&gt;IPv6 Router Advertisement Daemon&lt;/h2&gt;
&lt;p&gt;Install the router advertisement daemon or &lt;a class="reference external" href="http://www.litech.org/radvd/"&gt;radvd&lt;/a&gt; with:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;radvd
&lt;/pre&gt;
&lt;p&gt;Create file &lt;em&gt;/etc/radvd.conf&lt;/em&gt; and put your internal interface and prefix there:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
interface eth1
{
   AdvSendAdvert on;
   prefix 2001:db8:0:2::/64
   {
   };
};
&lt;/pre&gt;
&lt;p&gt;You can now start the daemon with&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo service radvd start
&lt;/pre&gt;
&lt;p&gt;That will enable router advertisements on the internal interface. See example
configuration files under &lt;em&gt;/usr/share/doc/radvd/examples&lt;/em&gt;. See also manual pages
for &lt;a class="reference external" href="http://linux.die.net/man/8/radvd"&gt;radvd(8)&lt;/a&gt; and
&lt;a class="reference external" href="http://linux.die.net/man/5/radvd.conf"&gt;radvd.conf(5)&lt;/a&gt; for more information.
The &lt;a class="reference external" href="http://linux.die.net/man/8/radvdump"&gt;radvdump(8)&lt;/a&gt; is a useful tool for
watching live router advertisement traffic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-rdnss-and-dnssl-options"&gt;
&lt;h2&gt;The RDNSS and DNSSL Options&lt;/h2&gt;
&lt;p&gt;Below is an example &lt;em&gt;radvd.conf&lt;/em&gt; which also advertises DNS servers with RDNSS
and DNS search path with DNSSL, both of which are specified in &lt;a class="reference external" href="http://tools.ietf.org/html/rfc6106"&gt;RFC 6106&lt;/a&gt;. This will work with Linux and Mac OS X
clients, but unfortunately Windows does not seem to support it.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
interface eth1
{
  AdvSendAdvert on;
  MinRtrAdvInterval 3;
  MaxRtrAdvInterval 10;

  prefix 2001:db8:0:1::/64
  {
  };

  RDNSS 2001:db8:0:1::a 2001:db8:0:1::b
  {
    AdvRDNSSLifetime 10;
  };

  DNSSL koo.fi
  {
    AdvDNSSLLifetime 10;
  };
};
&lt;/pre&gt;
&lt;p&gt;Restart radvd.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="dhcpv6"&gt;
&lt;h2&gt;DHCPv6&lt;/h2&gt;
&lt;p&gt;To support Windows, we must install a DHCPv6 compliant DHCP server, such as a
recent version of the ISC DHCP daemon:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install isc-dhcp-server
&lt;/pre&gt;
&lt;p&gt;Create file &lt;em&gt;/etc/dhcp/dhcpd6.conf&lt;/em&gt; and put something like this in there:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ddns-update-style none;

default-lease-time 7200;
max-lease-time 86400;

subnet6 2001:db8:0:2::/64 {
  range6
    2001:db8:0:2::1000
    2001:db8:0:2::1fff;

  option dhcp6.name-servers
    2001:db8:0:1::a,
    2001:db8:0:1::b;

  option dhcp6.domain-search
    &amp;quot;koo.fi&amp;quot;;
}
&lt;/pre&gt;
&lt;p&gt;We configured a pool of 4096 addresses here (::1000-1fff), plus DNS servers and search path.&lt;/p&gt;
&lt;p&gt;Start the dhcpv6 server:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo service isc-dhcp-server6 start
&lt;/pre&gt;
&lt;p&gt;If it fails, see &lt;em&gt;/var/log/syslog&lt;/em&gt; for error messages. Finally, if everything
went ok, add to default runlevels:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo update-rc.d isc-dhcp-server6 defaults
&lt;/pre&gt;
&lt;p&gt;Now you should be able to get an IPv6 address and DNS servers with a DHCP
client. Additional benefit with DHCP is that you can send more configuration
information, such as time server addresses, using DHCP options.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Neighbor_Discovery_Protocol"&gt;Neighbor Discovery Protocol&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://tools.ietf.org/html/rfc6106"&gt;IPv6 Router Advertisement Options for DNS Configuration (RFC 6106)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/8/radvd"&gt;radvd(8)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/5/radvd.conf"&gt;radvd.conf(5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/8/radvdump"&gt;radvdump(8)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.isc.org/software/dhcp"&gt;ISC DHCP daemon&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/5/dhcp-options"&gt;DHCP Options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="DHCPD"></category><category term="IPv6"></category><category term="RADVD"></category><category term="Ubuntu"></category><category term="Networking"></category></entry><entry><title>Python 2.7 Windows Installation Checklist</title><link href="https://mikko.kortelainen.io/blog/python-2-7-windows-installation-checklist/" rel="alternate"></link><published>2013-03-12T15:01:00+02:00</published><updated>2013-03-12T15:01:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-12:/blog/python-2-7-windows-installation-checklist/</id><summary type="html">&lt;p&gt;Installing Python on Windows is a bit more laborious than on Mac or Linux,
because there's a bit of manual configuring to do. Here's an installation
checklist to go through to get it done so that you have
&lt;a class="reference external" href="http://ipython.org"&gt;IPython&lt;/a&gt; ready, and you can install packages from
&lt;a class="reference external" href="https://pypi.python.org/pypi"&gt;PyPI&lt;/a&gt;. These instructions are …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Installing Python on Windows is a bit more laborious than on Mac or Linux,
because there's a bit of manual configuring to do. Here's an installation
checklist to go through to get it done so that you have
&lt;a class="reference external" href="http://ipython.org"&gt;IPython&lt;/a&gt; ready, and you can install packages from
&lt;a class="reference external" href="https://pypi.python.org/pypi"&gt;PyPI&lt;/a&gt;. These instructions are for Python 2.7.&lt;/p&gt;
&lt;div class="section" id="python"&gt;
&lt;h2&gt;1. Python&lt;/h2&gt;
&lt;p&gt;Download the Python 2.7 Windows Installer from the &lt;a class="reference external" href="http://python.org/download/"&gt;Python.org download page&lt;/a&gt;. Choose either 32-bit or 64-bit version.
Install it. Take note where you install it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pywin32"&gt;
&lt;h2&gt;2. PyWin32&lt;/h2&gt;
&lt;p&gt;Download &lt;a class="reference external" href="http://sourceforge.net/projects/pywin32/files/?source=navbar"&gt;Python for Windows extensions or &amp;quot;pywin32&amp;quot; here&lt;/a&gt;. Install it.
It should detect your Python directory. This is optional, but I recommend it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="setuptools"&gt;
&lt;h2&gt;3. Setuptools&lt;/h2&gt;
&lt;p&gt;Download &lt;a class="reference external" href="https://pypi.python.org/pypi/setuptools"&gt;setuptools from PyPi&lt;/a&gt;&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;For a 32-bit installation, you can use the
&lt;a class="reference external" href="https://pypi.python.org/pypi/setuptools#credits"&gt;setuptools-x.y-win32-py2.7.exe&lt;/a&gt;
file. Run the installation program, which should detect your installation path.&lt;/li&gt;
&lt;li&gt;For a 64-bit installation,
&lt;a class="reference external" href="https://pypi.python.org/pypi/setuptools#windows"&gt;download the ez_setup.py&lt;/a&gt;
and place it in your installation directory.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="your-path"&gt;
&lt;h2&gt;4. Your PATH&lt;/h2&gt;
&lt;p&gt;Edit your PATH. Open &lt;em&gt;My Computer&lt;/em&gt; properties, from there &lt;em&gt;Advanced Settings&lt;/em&gt;,
and open the Environment Variables property window. If you have a PATH variable
set already, edit that. Otherwise add an environment variable called &amp;quot;PATH&amp;quot; and
add your Python installation directory, and also the scripts directory. The
paths are separated by semicolons. For example:&lt;/p&gt;
&lt;blockquote&gt;
C:Python27;C:Python27Scripts;C:Python27ToolsScripts&lt;/blockquote&gt;
&lt;p&gt;Here's a screenshot:&lt;/p&gt;
&lt;p&gt;&lt;img alt="image0" src="https://mikko.kortelainen.io/blog/files/python27-install-checklist.png" /&gt;&lt;/p&gt;
&lt;p&gt;If you need other users, or system services to use Python, you can add it to the
System Path. If you only use it yourself, add it to your own path.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="ipython"&gt;
&lt;h2&gt;5. IPython&lt;/h2&gt;
&lt;p&gt;Open command prompt. Go to the installation folder you chose.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
c:
cd \
cd Python27
&lt;/pre&gt;
&lt;p&gt;If you are using the 64-bit version, now is the time to run the &lt;em&gt;ez_setup.py&lt;/em&gt;
which you downloaded earlier. The defaults are pretty much ok. If you have the
32-bit version, the setuptools should be installed already, so move on.&lt;/p&gt;
&lt;p&gt;You can install stuff from the &lt;a class="reference external" href="https://pypi.python.org/pypi"&gt;the Python Package Index&lt;/a&gt;
using the &lt;em&gt;easy_install&lt;/em&gt; command, which is in the Scripts folder. If you added
it into your path, you can run it from
anywhere.&lt;/p&gt;
&lt;p&gt;To get a nicer shell, let's install &lt;a class="reference external" href="http://ipython.org"&gt;IPython&lt;/a&gt;. Run these
commands (which were taken from
&lt;a class="reference external" href="http://ipython.org/ipython-doc/stable/install/install.html#windows"&gt;this page&lt;/a&gt;):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
easy_install distribute
easy_install pyreadline
easy_install ipython
&lt;/pre&gt;
&lt;p&gt;Now you can start the IPython shell by running the &lt;em&gt;ipython&lt;/em&gt; command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
C:\Python27&amp;gt;ipython
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)]
Type &amp;quot;copyright&amp;quot;, &amp;quot;credits&amp;quot; or &amp;quot;license&amp;quot; for more information.

IPython 0.13.1 -- An enhanced Interactive Python.
?         -&amp;gt; Introduction and overview of IPython's features.
%quickref -&amp;gt; Quick reference.
help      -&amp;gt; Python's own help system.
object?   -&amp;gt; Details about 'object', use 'object??' for extra details.

In [1]:
&lt;/pre&gt;
&lt;p&gt;Also, to get packages and libraries, just run easy_install to fetch and install it automatically.&lt;/p&gt;
&lt;p&gt;If you create your own modules and packages, you can put them in this directory:&lt;/p&gt;
&lt;blockquote&gt;
C:Python27Libsite-packages&lt;/blockquote&gt;
&lt;p&gt;That way you can import them in your scripts easily.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Python"></category><category term="Windows"></category></entry><entry><title>PostgreSQL Database Cluster Migration Notes</title><link href="https://mikko.kortelainen.io/blog/postgresql-database-cluster-migration-notes/" rel="alternate"></link><published>2013-03-12T08:38:00+02:00</published><updated>2013-03-12T08:38:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-12:/blog/postgresql-database-cluster-migration-notes/</id><summary type="html">&lt;p&gt;I had to migrate a pretty big database cluster from one server with PostgreSQL
8.4 to a new server with 9.2 There we multiple apps using the databases, and the
downtime had to be minimal. Luckily, the databases were split to multiple
schemas, and there were only a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I had to migrate a pretty big database cluster from one server with PostgreSQL
8.4 to a new server with 9.2 There we multiple apps using the databases, and the
downtime had to be minimal. Luckily, the databases were split to multiple
schemas, and there were only a few tables in a couple of schemas that were in
active use at the time of the migration.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="http://www.postgresql.org/docs/8.4/static/app-pgdump.html"&gt;pg_dump&lt;/a&gt; tool
was very helpful in this operation. First, I set up ssh public key
authentication between the &lt;em&gt;postgres&lt;/em&gt; users from the source to the destination
server. Then I ran the first full cluster dump to the new empty cluster. This
can be done while users are actively using the source database, as long as you
know which schemas, tables and sequences are in use, so that they can be copied
again after shutting down applications:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
postgres&amp;#64;source:~$ pg_dumpall | gzip | ssh destination 'gunzip | psql -e'
&lt;/pre&gt;
&lt;p&gt;The dump is gzipped and sent using ssh to the destination. Watching the run with
&lt;em&gt;top&lt;/em&gt; showed that gzip and ssh didn't use much CPU compared to what the pg_dump
and psql processes took. The -e option of &lt;em&gt;psql&lt;/em&gt; tells you which queries exactly
it is running.&lt;/p&gt;
&lt;p&gt;At this point, there's a snapshot of the source cluster in the destination, with
all the metadata, users etc.&lt;/p&gt;
&lt;p&gt;Next, after shutting down a particular application which uses a particular
database, the following copies just that database:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
postgres&amp;#64;source:~$ pg_dump --clean db1 | gzip | ssh destination 'gunzip | psql -e db1'
&lt;/pre&gt;
&lt;p&gt;The --clean option will actually drop all the objects in the destination
database and re-create them. Note the destination database name in the psql
command.&lt;/p&gt;
&lt;p&gt;Another database was so big, that I had to copy individual schemas instead of
the whole database, because that would have taken too much time. The following
copies just one schema:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
postgres&amp;#64;source:~$ pg_dump --clean --schema schema1 db2 | gzip | ssh destination 'gunzip | psql -e db2'
&lt;/pre&gt;
&lt;p&gt;If the whole schema is too big, this one can be used to copy a single table:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
postgres&amp;#64;source:~$ pg_dump --clean --table schema2.table1 db2 | gzip | ssh destination 'gunzip | psql -e db2'
&lt;/pre&gt;
&lt;p&gt;The --clean table dump also drops and re-creates the sequences related to the
table, so that your sequence numbers are kept intact.&lt;/p&gt;
&lt;p&gt;With those commands, it is pretty easy to shut down an application, migrate the
data, start up the particular app, and move to migrating the next one. Even if
the apps use the same databases and schemas. Just be sure to know which app
modifies which database objects. And remember that the schema and table specific
dumps will not by default dump blobs.&lt;/p&gt;
</content><category term="Blog"></category><category term="PostgreSQL"></category></entry><entry><title>Sonera CStream Messaging Web Service API with Python and SUDS</title><link href="https://mikko.kortelainen.io/blog/sonera-cstream/" rel="alternate"></link><published>2013-03-11T23:51:00+02:00</published><updated>2013-03-11T23:51:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-11:/blog/sonera-cstream/</id><summary type="html">&lt;p&gt;In this article I will show you how to use the &lt;a class="reference external" href="http://www.sonera.fi"&gt;Sonera&lt;/a&gt; CStream Messaging Web Service API to send an SMS using Python, and a library called&amp;nbsp; SUDS. The CStream API is two-way service for both sending and receiving messages. You obviously need to pay for the service to get …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this article I will show you how to use the &lt;a class="reference external" href="http://www.sonera.fi"&gt;Sonera&lt;/a&gt; CStream Messaging Web Service API to send an SMS using Python, and a library called&amp;nbsp; SUDS. The CStream API is two-way service for both sending and receiving messages. You obviously need to pay for the service to get access. After you have your credentials, you can start using the service.&lt;/p&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://fedorahosted.org/suds/"&gt;SUDS&lt;/a&gt; is a lightweight SOAP Python client for exploring and using web services. A recent version can be installed on Debian based distros with &lt;em&gt;&amp;quot;sudo apt-get install python-suds&amp;quot;&lt;/em&gt;, or on almost anything with &lt;em&gt;&amp;quot;pip install suds&amp;quot;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The one thing good to know before starting out, is that the Sonera web service uses WS Security for authentication, which is found in the suds.wsse module.&lt;/p&gt;
&lt;p&gt;Let's start hacking in iPython:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
kortsi&amp;#64;localhost:~$ ipython
Python 2.7.3 (default, Sep 26 2012, 21:51:14)
Type &amp;quot;copyright&amp;quot;, &amp;quot;credits&amp;quot; or &amp;quot;license&amp;quot; for more information.

IPython 0.13.1.rc2 -- An enhanced Interactive Python.
?         -&amp;gt; Introduction and overview of IPython's features.
%quickref -&amp;gt; Quick reference.
          -&amp;gt; Python's own help system.
object    -&amp;gt; Details about 'object', use 'object??' for extra details.

In [1]: import logging

In [2]: logging.basicConfig(level=logging.DEBUG)

In [3]: logging.getLogger('suds.client').setLevel(logging.DEBUG)

In [4]: from suds.client import Client

In [5]: client = Client('https://saarni.front.sonera.fi/ws/messaging-v2.wsdl')
&lt;/pre&gt;
&lt;p&gt;At this point you should see a lot of debug messages on the screen. Thats the SUDS querying the WSDL schema and finding out what's possible. You can take a look at it if it you are interested, but there is a better way to explore the metadata.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
In [6]: print client

Suds ( https://fedorahosted.org/suds/ )  version: 0.4.1 (beta)  build: R703-20101015

Service ( messaging-v2Service ) tns=&amp;quot;http://www.lekab.com/schema/messaging-v2/messages&amp;quot;
   Prefixes (1)
      ns0 = &amp;quot;http://www.lekab.com/schema/messaging-v2/messages&amp;quot;
   Ports (1):
      (messaging-v2Soap11)
         Methods (3):
            GetIncomingMessages(MessageIds messageIds, Attributes attributes, )
            GetMessageStatus(MessageIds messageIds, Attributes attributes, )
            Send(xs:string sender, Recipients recipients, xs:boolean replyable, xs:string conversationId, Priority priority, xs:dateTime scheduledDelivery, xs:dateTime validTo, xs:string tariff, xs:string contentCategory, xs:string contentMetaData, xs:double vat, xs:string referenceId, Data data, Attributes attributes, )
         Types (21):
            Attachment
            Attachments
            Attribute
            Attributes
            Data
            ErrorDetail
            ErrorDetails
            IncomingMessage
            IncomingMessages
            MessageIds
            MessageStatus
            MessageStatuses
            MmsData
            MmsPayload
            OutgoingMessage
            Payload
            Priority
            Recipients
            SmsData
            SmsPayload
            Value
&lt;/pre&gt;
&lt;p&gt;The list of available methods and and data types is what we are interested in.&lt;/p&gt;
&lt;p&gt;The three methods there match the API specification. The names are pretty much self-explanatory:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;em&gt;Send()&lt;/em&gt; sends text messages&lt;/li&gt;
&lt;li&gt;&lt;em&gt;GetMessageStatus()&lt;/em&gt; queries the status of sent messages&lt;/li&gt;
&lt;li&gt;&lt;em&gt;GetIncomingMessages()&lt;/em&gt; retrieves incoming messages&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To invoke those methods, we must be able to create data in specified types. To send an SMS, we need to create an &lt;em&gt;SmsData&lt;/em&gt; object, wrapped in a &lt;em&gt;Data&lt;/em&gt; object. We can have SUDS create them for us:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Data'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;smsdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SmsData'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;smsdata&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;sms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmsData&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmsPayload&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;udh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;replaceIfPresent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;flash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;That shows what the &lt;em&gt;Data&lt;/em&gt; should look like. Let's also create an &lt;em&gt;SmsPayload&lt;/em&gt; object:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;11&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SmsPayload'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmsPayload&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;udh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;According to the specification, the message attribute must be a &amp;quot;base64 encoded UTF-8 encoded string&amp;quot;. Let's test with a string that requires more than plain ASCII:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;testmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;'Tämä on testi! (&amp;quot;This is a test!&amp;quot; in Finnish)'&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base64&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encodestring&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;testmessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utf8'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmsPayload&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;VMOkbcOkIG9uIHRlc3RpISAoIlRoaXMgaXMgYSB0ZXN0ISIgaW4gRmlubmlzaCk=&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;udh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;smsdata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;sms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmsData&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SmsPayload&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;VMOkbcOkIG9uIHRlc3RpISAoIlRoaXMgaXMgYSB0ZXN0ISIgaW4gRmlubmlzaCk=&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;udh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;encoding&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;replaceIfPresent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;flash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;         &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Attributes&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;               &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;empty&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;            &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now we have a payload set. The &lt;em&gt;Data&lt;/em&gt; object is now ready for sending. We still need to create a list of recipients:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;recipients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Recipients'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;recipients&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'358001234567'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;21&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt; &lt;span class="n"&gt;recipients&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Recipients&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;   &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="s2"&gt;&amp;quot;358001234567&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The recipient number must be a string, and it must have a country code. A sender id or number is also required, but it can be whatever you choose. We can give it directly to the &lt;em&gt;Send()&lt;/em&gt; method when we send the message. But before that, we must set up authentication:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
In [22]: from suds.wsse import Security, UsernameToken, Timestamp

In [23]: security = Security()

In [24]: username = UsernameToken('username', 'secretpassword')

In [25]: security.tokens.append(username)

In [26]: timestamp = Timestamp(validity=120)

In [27]: security.tokens.append(timestamp)

In [28]: client.set_options(wsse=security)
&lt;/pre&gt;
&lt;p&gt;We set up a username/password token, and a timestamp. Now we have 120 seconds of time to send a message using the security tokens.&lt;/p&gt;
&lt;p&gt;At this point, we should have everything we need to send our message. Use the &lt;em&gt;Send()&lt;/em&gt; method:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
In [29]: client.service.Send(sender='SENDERID', recipients=recipients, data=data)
&lt;/pre&gt;
&lt;p&gt;You will get a reply from the remote server. It will either tell you that it failed for some reason, but if everything went ok, the message was queued for delivery, and the response object will look something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Out[29]:
(reply){
   messageStatus[] =
      (MessageStatus){
         statusCode = 0
         statusText = &amp;quot;QUEUED&amp;quot;
         id = &amp;quot;1-9876543&amp;quot;
         sender = &amp;quot;SENDERID&amp;quot;
         recipient = &amp;quot;358001234567&amp;quot;
         time = 2013-03-11 15:52:37.000984
         billingStatus = 0
         attributes =
            (Attributes){
               attribute[] =
                  (Attribute){
                     name = &amp;quot;NumberOfMessages&amp;quot;
                     value =
                        (Value){
                           integer = 1
                        }
                  },
                  (Attribute){
                     name = &amp;quot;NumberOfCharacters&amp;quot;
                     value =
                        (Value){
                           integer = 45
                        }
                  },
            }
      },
   attributes =
      (Attributes){
         attribute[] =
            (Attribute){
               name = &amp;quot;TotalNumberOfMessages&amp;quot;
               value =
                  (Value){
                     integer = 1
                  }
            },
      }
 }
&lt;/pre&gt;
&lt;p&gt;The recipient should receive the message shortly.&lt;/p&gt;
&lt;p&gt;To wrap it up, let's make a simple class out of it. Put this to a file called &lt;em&gt;cstream.py&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;WSDL_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://saarni.front.sonera.fi/ws/messaging-v2.wsdl'&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;base64&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;encodestring&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;b64enc&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;suds.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;suds.wsse&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Security&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UsernameToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleSmsSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Sends an SMS using CStream Web Service API

Give your credentials as arguments to the constructor. Example:

  sender = SimpleSmsSender('username', 'secretpassword')
  &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="fm"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;WSDL_URL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="sd"&gt;&amp;quot;&amp;quot;&amp;quot;Give sender id, recipient number and message as strings. The message
can be a unicode string. Example:

  sender.send('SENDERID', '358001234567', u'Hello world!')
    &amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;factory&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Data'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;smsdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SmsData'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sms&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;smsdata&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'SmsPayload'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;b64enc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'utf8'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;smsdata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;recipients&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Recipients'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;recipients&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recipient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;security&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Security&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UsernameToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;security&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Timestamp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;security&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wsse&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;security&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                                    &lt;span class="n"&gt;recipients&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;recipients&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                                    &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;To use:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;cstream&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SimpleSmsSender&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SimpleSmsSender&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'username'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'secretpassword'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;In&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'FROM ME'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'358001234567'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;u&lt;/span&gt;&lt;span class="s1"&gt;'Hello world'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;That's it! The receiving of messages, the checking of message delivery status, and the handling of exceptions are left as exercises to the reader (and to myself).&lt;/p&gt;
&lt;div class="section" id="useful-links"&gt;
&lt;h2&gt;&amp;nbsp;Useful links:&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://fedorahosted.org/suds/wiki/Documentation"&gt;Get Started with SUDS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://jortel.fedorapeople.org/suds/doc/"&gt;SUDS API Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Python"></category></entry><entry><title>Init Script for Daemonizing Non-Forking Processes</title><link href="https://mikko.kortelainen.io/blog/init-script-for-daemonizing-non-forking-processes/" rel="alternate"></link><published>2013-03-09T15:18:00+02:00</published><updated>2013-03-09T15:18:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-09:/blog/init-script-for-daemonizing-non-forking-processes/</id><summary type="html">&lt;p&gt;Sometimes you have an executable which does not fork to the background, but you need to control it with init scripts, so that it does indeed run in the background. Here's a pretty generic init script for that. It allows you to configure these:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;DAEMON_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;My Little Daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_EXECUTABLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/opt …&lt;/span&gt;&lt;/pre&gt;</summary><content type="html">&lt;p&gt;Sometimes you have an executable which does not fork to the background, but you need to control it with init scripts, so that it does indeed run in the background. Here's a pretty generic init script for that. It allows you to configure these:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;DAEMON_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;My Little Daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_EXECUTABLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/opt/my_daemon/my_daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_HOMEDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/opt/my_daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_PIDFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/run/my_daemon.pid&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_LOGFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/log/my_daemon.log&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;INIT_SLEEPTIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;The script changes directory to the &lt;em&gt;DAEMON_HOMEDIR&lt;/em&gt;, runs &lt;em&gt;DAEMON_EXECUTABLE&lt;/em&gt; with &lt;em&gt;DAEMON_OPTIONS&lt;/em&gt; and saves the new process id to the &lt;em&gt;DAEMON_PIDFILE&lt;/em&gt; file. Remember to use different pidfile for every daemon.&lt;/p&gt;
&lt;p&gt;The script also checks whether the process is up and running after &lt;em&gt;INIT_SLEEPTIME&lt;/em&gt; seconds. If not, it will fail. It will do the check after stopping as well.&lt;/p&gt;
&lt;p&gt;All stdout/stderr output is sent to &lt;em&gt;DAEMON_LOGFILE&lt;/em&gt;. If you don't want to log the output, set it to &amp;quot;/dev/null&amp;quot;.&lt;/p&gt;
&lt;p&gt;You can control init scripts with this part in the beginning of the file:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="c1"&gt;### BEGIN INIT INFO
# Provides:          my_daemon
# Required-Start:    $network
# Required-Stop:     $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Runs the non-forking program in the background
### END INIT INFO&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Ubuntu/Debian &lt;em&gt;update-rc.d&lt;/em&gt; will use those defaults to install it. So after you drop the script under &lt;em&gt;/etc/init.d&lt;/em&gt; with the name &lt;em&gt;my_daemon&lt;/em&gt;, you can install it using this:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;update-rc.d&lt;span class="w"&gt; &lt;/span&gt;my_daemon&lt;span class="w"&gt; &lt;/span&gt;defaults
&lt;/pre&gt;
&lt;p&gt;To disable temporarily:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo update-rc.d my_daemon disable
&lt;/pre&gt;
&lt;p&gt;To re-enable:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo update-rc.d my_daemon enable
&lt;/pre&gt;
&lt;p&gt;To remove:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo update-rc.d -f my_daemon remove
&lt;/pre&gt;
&lt;p&gt;This script does not change running user id from root to something else, so be careful with it.&lt;/p&gt;
&lt;p&gt;To start up the daemon, run:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo service my_daemon start
&lt;/pre&gt;
&lt;p&gt;To stop:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo service my_daemon stop
&lt;/pre&gt;
&lt;p&gt;Restart:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo service my_daemon restart
&lt;/pre&gt;
&lt;p&gt;See status:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo service my_daemon status
&lt;/pre&gt;
&lt;div class="section" id="the-script"&gt;
&lt;h2&gt;The Script&lt;/h2&gt;
&lt;p&gt;Enough explanation. Here's the script:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="ch"&gt;#!/bin/sh
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;### BEGIN INIT INFO
# Provides:          my_daemon
# Required-Start:    $network
# Required-Stop:     $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Runs the non-forking program in the background
### END INIT INFO
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# Defaults
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;My Little Daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_EXECUTABLE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/opt/my_daemon/my_daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_HOMEDIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/opt/my_daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_PIDFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/run/my_daemon.pid&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_LOGFILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/var/log/my_daemon.log&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;INIT_SLEEPTIME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;2&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Defaults can be overridden in this file
&lt;/span&gt;&lt;span class="nv"&gt;DAEMON_DEFAULTS_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/etc/default/my_daemon&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/sbin:/bin:/usr/sbin:/usr/bin&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Load alternate configuration if exists
&lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_DEFAULTS_FILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_DEFAULTS_FILE&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;.&lt;span class="w"&gt; &lt;/span&gt;/lib/lsb/init-functions&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Usually no need to edit below this point. Just have these ready:
#
# * DAEMON_EXECUTABLE - full path to the executable
# * DAEMON_OPTIONS    - options to pass to the executable
# * DAEMON_NAME       - a decriptive name
# * DAEMON_HOMEDIR    - place where to cd before running
# * DAEMON_PIDFILE    - pid file name
# * DAEMON_LOGFILE    - log file name
# * INIT_SLEEPTIME    - how long to wait for startup and shutdown
#
# The rest will be taken care of. Executable is run with &amp;quot;nohup&amp;quot;, so no
# need to fork.
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;is_running&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c1"&gt;# Test whether pid file exists or not
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;# Test whether process is running or not
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PID&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;ps&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;/dev/null&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;# Is running
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;root_only&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;id&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;0&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Only root should run this operation&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;run&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is_running&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;PID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Daemon is already running as PID &lt;/span&gt;&lt;span class="nv"&gt;$PID&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_HOMEDIR&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;nohup&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_EXECUTABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_OPTIONS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="nv"&gt;$DAEMON_LOGFILE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PID&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;sleep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INIT_SLEEPTIME&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="w"&gt; &lt;/span&gt;is_running&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Daemon died immediately after starting. Please check your logs and configurations.&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Daemon is running as PID &lt;/span&gt;&lt;span class="nv"&gt;$PID&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;stop&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is_running&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PID&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;kill&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$PID&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;sleep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INIT_SLEEPTIME&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is_running&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;is_running&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;waiting for daemon to die (PID &lt;/span&gt;&lt;span class="nv"&gt;$PID&lt;/span&gt;&lt;span class="s2"&gt;)&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;sleep&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$INIT_SLEEPTIME&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;start&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;root_only&lt;span class="w"&gt;
    &lt;/span&gt;log_daemon_msg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Starting &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_NAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;run&lt;span class="w"&gt;
    &lt;/span&gt;log_end_msg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;stop&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;root_only&lt;span class="w"&gt;
    &lt;/span&gt;log_daemon_msg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Stopping &lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_NAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;stop&lt;span class="w"&gt;
    &lt;/span&gt;log_end_msg&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;restart&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;root_only&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;stop&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;status&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;status_of_proc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_PIDFILE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_EXECUTABLE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$DAEMON_NAME&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;*&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Usage: &lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt; {start|stop|restart|status}&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;esac&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Shell scripts"></category><category term="Sysadmin"></category><category term="Ubuntu"></category></entry><entry><title>HP ProLiant Management Component Pack on Ubuntu</title><link href="https://mikko.kortelainen.io/blog/hp-proliant-management-component-pack-on-ubuntu/" rel="alternate"></link><published>2013-03-08T12:16:00+02:00</published><updated>2013-03-08T12:16:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-08:/blog/hp-proliant-management-component-pack-on-ubuntu/</id><summary type="html">&lt;p&gt;HP seems to have set up a package repository for Ubuntu 12.04, which is an improvement since I last checked a few years ago. To use the repo, add the following line to /etc/apt/sources.list:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
deb http://downloads.linux.hp.com/downloads/ManagementComponentPack/ubuntu precise current/non-free …&lt;/pre&gt;</summary><content type="html">&lt;p&gt;HP seems to have set up a package repository for Ubuntu 12.04, which is an improvement since I last checked a few years ago. To use the repo, add the following line to /etc/apt/sources.list:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
deb http://downloads.linux.hp.com/downloads/ManagementComponentPack/ubuntu precise current/non-free
&lt;/pre&gt;
&lt;p&gt;Run &amp;quot;sudo apt-get update&amp;quot;.&lt;/p&gt;
&lt;p&gt;You can install a number of software packages from the repository:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;strong&gt;hpsmh&lt;/strong&gt;: HP System Management Homepage&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hp-smh-template&lt;/strong&gt;: HP System Management Homepage Templates&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;cpqacuxe&lt;/strong&gt;: HP Array Configuration Utility, web-based&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hp-snmp-agents&lt;/strong&gt;: Insight Management SNMP Agents for HP ProLiant Systems&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hponcfg&lt;/strong&gt;: RILOE II/iLO online configuration utility&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hp-health&lt;/strong&gt;: HP System Health Application and Command line Utility Package&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;hpacucli&lt;/strong&gt;: HP Command Line Array Configuration Utility&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ams&lt;/strong&gt;: Agentless Monitoring Service for HP ProLiant Gen8 Systems&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I installed the iLO configuration utility, System Health App and Array Configuration command line utility.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:/etc/apt#&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;hponcfg&lt;span class="w"&gt; &lt;/span&gt;hp-health&lt;span class="w"&gt; &lt;/span&gt;hpacucli
&lt;/pre&gt;
&lt;p&gt;I couldn't find a working GPG key so you need to press y or force package installation.&lt;/p&gt;
&lt;div class="section" id="useful-commands"&gt;
&lt;h2&gt;Useful Commands&lt;/h2&gt;
&lt;p&gt;You can blink the UID light with the &lt;em&gt;hpuid&lt;/em&gt; command.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;hpasmcli&lt;/em&gt; is a tool to show and set various system parameters.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
hpasmcli&amp;gt; show powermeter
Power Meter #1
    Power Reading  : 224

hpasmcli&amp;gt; show powersupply
Power supply #1
    Present  : Yes
    Redundant: No
    Condition: Ok
    Hotplug  : Supported
Power supply #2
    Present  : Yes
    Redundant: No
    Condition: FAILED
    Hotplug  : Supported
&lt;/pre&gt;
&lt;p&gt;A command called &amp;quot;hplog&amp;quot; can be used to view the log:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt;

&lt;/span&gt;ID&lt;span class="w"&gt;   &lt;/span&gt;Severity&lt;span class="w"&gt;       &lt;/span&gt;Initial&lt;span class="w"&gt; &lt;/span&gt;Time&lt;span class="w"&gt;      &lt;/span&gt;Update&lt;span class="w"&gt; &lt;/span&gt;Time&lt;span class="w"&gt;       &lt;/span&gt;Count&lt;span class="w"&gt;
&lt;/span&gt;-------------------------------------------------------------&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="m"&gt;1026&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Repaired&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:44&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:46&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;LOG:&lt;span class="w"&gt; &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Supplies&lt;span class="w"&gt; &lt;/span&gt;Not&lt;span class="w"&gt; &lt;/span&gt;Redundant&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="m"&gt;1027&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Repaired&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:46&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:48&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;LOG:&lt;span class="w"&gt; &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Supply:&lt;span class="w"&gt; &lt;/span&gt;General&lt;span class="w"&gt; &lt;/span&gt;Failure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Supply&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="m"&gt;1028&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Repaired&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:46&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:48&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;LOG:&lt;span class="w"&gt; &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Supplies&lt;span class="w"&gt; &lt;/span&gt;Not&lt;span class="w"&gt; &lt;/span&gt;Redundant&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="m"&gt;1029&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Repaired&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:48&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:49&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;LOG:&lt;span class="w"&gt; &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Supply:&lt;span class="w"&gt; &lt;/span&gt;General&lt;span class="w"&gt; &lt;/span&gt;Failure&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Supply&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="m"&gt;1030&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Repaired&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:48&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;13&lt;/span&gt;:49&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;04&lt;/span&gt;/10/2012&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0001&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;LOG:&lt;span class="w"&gt; &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;Power&lt;span class="w"&gt; &lt;/span&gt;Supplies&lt;span class="w"&gt; &lt;/span&gt;Not&lt;span class="w"&gt; &lt;/span&gt;Redundant
&lt;/pre&gt;
&lt;p&gt;And&amp;nbsp;show system health information (fans, power supplies, temperatures):&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt;
&lt;/span&gt;ID&lt;span class="w"&gt;     &lt;/span&gt;TYPE&lt;span class="w"&gt;        &lt;/span&gt;LOCATION&lt;span class="w"&gt;      &lt;/span&gt;STATUS&lt;span class="w"&gt;  &lt;/span&gt;REDUNDANT&lt;span class="w"&gt; &lt;/span&gt;FAN&lt;span class="w"&gt; &lt;/span&gt;SPEED&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Var.&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt;   &lt;/span&gt;I/O&lt;span class="w"&gt; &lt;/span&gt;Zone&lt;span class="w"&gt;        &lt;/span&gt;Normal&lt;span class="w"&gt;     &lt;/span&gt;Yes&lt;span class="w"&gt;     &lt;/span&gt;Medium&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Var.&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt;   &lt;/span&gt;I/O&lt;span class="w"&gt; &lt;/span&gt;Zone&lt;span class="w"&gt;        &lt;/span&gt;Normal&lt;span class="w"&gt;     &lt;/span&gt;Yes&lt;span class="w"&gt;     &lt;/span&gt;Medium&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;45&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Var.&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt;   &lt;/span&gt;Processor&lt;span class="w"&gt; &lt;/span&gt;Zone&lt;span class="w"&gt;  &lt;/span&gt;Normal&lt;span class="w"&gt;     &lt;/span&gt;Yes&lt;span class="w"&gt;     &lt;/span&gt;Medium&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;41&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Var.&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt;   &lt;/span&gt;Processor&lt;span class="w"&gt; &lt;/span&gt;Zone&lt;span class="w"&gt;  &lt;/span&gt;Normal&lt;span class="w"&gt;     &lt;/span&gt;Yes&lt;span class="w"&gt;     &lt;/span&gt;Low&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;36&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Var.&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt;   &lt;/span&gt;Processor&lt;span class="w"&gt; &lt;/span&gt;Zone&lt;span class="w"&gt;  &lt;/span&gt;Normal&lt;span class="w"&gt;     &lt;/span&gt;Yes&lt;span class="w"&gt;     &lt;/span&gt;Low&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;36&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Var.&lt;span class="w"&gt; &lt;/span&gt;Speed&lt;span class="w"&gt;   &lt;/span&gt;Processor&lt;span class="w"&gt; &lt;/span&gt;Zone&lt;span class="w"&gt;  &lt;/span&gt;Normal&lt;span class="w"&gt;     &lt;/span&gt;Yes&lt;span class="w"&gt;     &lt;/span&gt;Low&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;36&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt;
&lt;/span&gt;ID&lt;span class="w"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;TYPE&lt;span class="w"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;LOCATION&lt;span class="w"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;STATUS&lt;span class="w"&gt;&amp;nbsp; &lt;/span&gt;REDUNDANT&lt;span class="w"&gt;
&amp;nbsp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;&amp;nbsp; &lt;/span&gt;Standard&lt;span class="w"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Pwr.&lt;span class="w"&gt; &lt;/span&gt;Supply&lt;span class="w"&gt; &lt;/span&gt;Bay&lt;span class="w"&gt; &lt;/span&gt;Normal&lt;span class="w"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;No&lt;span class="w"&gt;
&amp;nbsp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;&amp;nbsp; &lt;/span&gt;Standard&lt;span class="w"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Pwr.&lt;span class="w"&gt; &lt;/span&gt;Supply&lt;span class="w"&gt; &lt;/span&gt;Bay&lt;span class="w"&gt; &lt;/span&gt;Failed&lt;span class="w"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;No&lt;span class="w"&gt;

&lt;/span&gt;root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt;
&lt;/span&gt;ID&lt;span class="w"&gt;     &lt;/span&gt;TYPE&lt;span class="w"&gt;        &lt;/span&gt;LOCATION&lt;span class="w"&gt;      &lt;/span&gt;STATUS&lt;span class="w"&gt;    &lt;/span&gt;CURRENT&lt;span class="w"&gt;  &lt;/span&gt;THRESHOLD&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Sensor&lt;span class="w"&gt; &lt;/span&gt;I/O&lt;span class="w"&gt; &lt;/span&gt;Zone&lt;span class="w"&gt;        &lt;/span&gt;Normal&lt;span class="w"&gt;   &lt;/span&gt;105F/&lt;span class="w"&gt; &lt;/span&gt;41C&lt;span class="w"&gt; &lt;/span&gt;158F/&lt;span class="w"&gt; &lt;/span&gt;70C&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Sensor&lt;span class="w"&gt; &lt;/span&gt;Ambient&lt;span class="w"&gt;         &lt;/span&gt;Normal&lt;span class="w"&gt;    &lt;/span&gt;68F/&lt;span class="w"&gt; &lt;/span&gt;20C&lt;span class="w"&gt; &lt;/span&gt;102F/&lt;span class="w"&gt; &lt;/span&gt;39C&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Sensor&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;Normal&lt;span class="w"&gt;    &lt;/span&gt;86F/&lt;span class="w"&gt; &lt;/span&gt;30C&lt;span class="w"&gt; &lt;/span&gt;260F/127C&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Sensor&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;Normal&lt;span class="w"&gt;    &lt;/span&gt;86F/&lt;span class="w"&gt; &lt;/span&gt;30C&lt;span class="w"&gt; &lt;/span&gt;260F/127C&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Sensor&lt;span class="w"&gt; &lt;/span&gt;Pwr.&lt;span class="w"&gt; &lt;/span&gt;Supply&lt;span class="w"&gt; &lt;/span&gt;Bay&lt;span class="w"&gt; &lt;/span&gt;Normal&lt;span class="w"&gt;   &lt;/span&gt;111F/&lt;span class="w"&gt; &lt;/span&gt;44C&lt;span class="w"&gt; &lt;/span&gt;170F/&lt;span class="w"&gt; &lt;/span&gt;77C&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Sensor&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;Normal&lt;span class="w"&gt;    &lt;/span&gt;86F/&lt;span class="w"&gt; &lt;/span&gt;30C&lt;span class="w"&gt; &lt;/span&gt;260F/127C&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="m"&gt;7&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;Basic&lt;span class="w"&gt; &lt;/span&gt;Sensor&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;Normal&lt;span class="w"&gt;    &lt;/span&gt;86F/&lt;span class="w"&gt; &lt;/span&gt;30C&lt;span class="w"&gt; &lt;/span&gt;260F/127C
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="array-configuration-utility"&gt;
&lt;h2&gt;Array Configuration Utility&lt;/h2&gt;
&lt;p&gt;The &amp;quot;hpacucli&amp;quot; is a Smart Array configuration tool. Some examples (the prompt is the =&amp;gt;):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;host:~# hpacucli
HP Array Configuration Utility CLI 9.30.15.0
Detecting Controllers...Done.
Type &amp;quot;help&amp;quot; for a list of supported commands.
Type &amp;quot;exit&amp;quot; to close the console.
=&amp;gt; ctrl all show

Smart Array P400 in Slot 3                (sn: P61630D9SV063I)

=&amp;gt; ctrl slot=3 show

Smart Array P400 in Slot 3
   Bus Interface: PCI
   Slot: 3
   Serial Number: P61630D9SV063I
   Cache Serial Number: PA2270H9VV23RN
   RAID 6 (ADG) Status: Enabled
   Controller Status: OK
   Hardware Revision: D
   Firmware Version: 7.22
   Rebuild Priority: Medium
   Expand Priority: Medium
   Surface Scan Delay: 3 secs
   Surface Scan Mode: Idle
   Wait for Cache Room: Disabled
   Surface Analysis Inconsistency Notification: Disabled
   Post Prompt Timeout: 15 secs
   Cache Board Present: True
   Cache Status: OK
   Cache Ratio: 25% Read / 75% Write
   Drive Write Cache: Enabled
   Total Cache Size: 512 MB
   Total Cache Memory Available: 464 MB
   No-Battery Write Cache: Enabled
   Cache Backup Power Source: Batteries
   Battery/Capacitor Count: 1
   Battery/Capacitor Status: OK
   SATA NCQ Supported: True

=&amp;gt; ctrl slot=3 array all show

Smart Array P400 in Slot 3

   array A (SAS, Unused Space: 0  MB)

=&amp;gt; ctrl slot=3 array A show

Smart Array P400 in Slot 3

   Array: A
      Interface Type: SAS
      Unused Space: 0  MB
      Status: OK
      Array Type: Data

=&amp;gt; ctrl slot=3 physicaldrive all show

Smart Array P400 in Slot 3

&amp;nbsp;&amp;nbsp; array A

&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; physicaldrive 1I:1:1 (port 1I:box 1:bay 1, SAS, 146 GB, OK)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; physicaldrive 1I:1:2 (port 1I:box 1:bay 2, SAS, 146 GB, OK)
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; physicaldrive 1I:1:3 (port 1I:box 1:bay 3, SAS, 146 GB, OK)
&lt;/pre&gt;
&lt;p&gt;The utility also understands commands directly from the command line:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt;

&lt;/span&gt;Smart&lt;span class="w"&gt; &lt;/span&gt;Array&lt;span class="w"&gt; &lt;/span&gt;P400&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Slot&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;Controller&lt;span class="w"&gt; &lt;/span&gt;Status:&lt;span class="w"&gt; &lt;/span&gt;OK&lt;span class="w"&gt;
   &lt;/span&gt;Cache&lt;span class="w"&gt; &lt;/span&gt;Status:&lt;span class="w"&gt; &lt;/span&gt;OK&lt;span class="w"&gt;
   &lt;/span&gt;Battery/Capacitor&lt;span class="w"&gt; &lt;/span&gt;Status:&lt;span class="w"&gt; &lt;/span&gt;OK
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="e-mail-alerts"&gt;
&lt;h2&gt;E-mail Alerts&lt;/h2&gt;
&lt;p&gt;To get e-mail out of the system, I installed Postfix.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;postfix&lt;span class="w"&gt; &lt;/span&gt;mailutils
&lt;/pre&gt;
&lt;p&gt;Select &amp;quot;Internet Site&amp;quot;. After installation, do a reconfiguration:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
root&amp;#64;host:~# dpkg-reconfigure postfix
&lt;/pre&gt;
&lt;p&gt;Select &amp;quot;Internet Site&amp;quot; again. Give your username as the recipient for root and postmaster.&lt;/p&gt;
&lt;p&gt;Use the default destination list. No forcing of synchronous updates.&lt;/p&gt;
&lt;p&gt;Next question is about where to accept mail from. The default is localhost only, which is good for my purposes, because this is not a proper mail server.&lt;/p&gt;
&lt;p&gt;For the rest of the questions I just use defaults. For additional security, you can edit the &lt;em&gt;/etc/postfix/main.cf&lt;/em&gt; and change the line&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
inet_interfaces = all
&lt;/pre&gt;
&lt;p&gt;to:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
inet_interfaces = loopback-only
&lt;/pre&gt;
&lt;p&gt;Restart Postfix. To forward all important mail from the system to yourself, edit &lt;em&gt;/etc/aliases&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
postmaster: root
root:       your&amp;#64;email.here
&lt;/pre&gt;
&lt;p&gt;Run command&lt;/p&gt;
&lt;pre class="literal-block"&gt;
root&amp;#64;host:~# newaliases
&lt;/pre&gt;
&lt;p&gt;Now you will get all root mail. I also like to change root full name, which will show up as the sender of the e-mail. This way I can see which host's root is sending me mail.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
chfn -f &amp;quot;Hostname Root&amp;quot; root
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="hardware-health-check-script"&gt;
&lt;h2&gt;&amp;nbsp;Hardware Health Check Script&lt;/h2&gt;
&lt;p&gt;For Smart Array checking, I wrote this little script and put it in &lt;em&gt;/usr/local/sbin/smart_array_check&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="ch"&gt;#!/bin/sh
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;SLOT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;3&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# Your controller slot number
&lt;/span&gt;&lt;span class="nv"&gt;ARRAY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;A&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# Your array letter
&lt;/span&gt;&lt;span class="nv"&gt;EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# You can put your e-mail address here
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# This function is called if checks don't pass. Send e-mail.
&lt;/span&gt;Notify&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nv"&gt;SUBJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SUBJECT&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Check&lt;span class="w"&gt; &lt;/span&gt;date:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;date&lt;span class="w"&gt; &lt;/span&gt;+&lt;span class="s2"&gt;&amp;quot;%F %T%:::z&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Controller&lt;span class="w"&gt; &lt;/span&gt;Status:&lt;span class="w"&gt;
    &lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Array&lt;span class="w"&gt; &lt;/span&gt;Status:&lt;span class="w"&gt;
    &lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;array&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ARRAY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Physical&lt;span class="w"&gt; &lt;/span&gt;Drives:&lt;span class="w"&gt;
    &lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;physicaldrive&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Physical&lt;span class="w"&gt; &lt;/span&gt;Drive&lt;span class="w"&gt; &lt;/span&gt;Details:&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;DRIVE&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;physicaldrive&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;physicaldrive&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;awk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'{ print $2 }'&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;physicaldrive&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$DRIVE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mail&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$SUBJECT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$EMAIL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Check that there's a line saying 'Controller Status: OK' etc.
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Controller Status: OK'&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Notify&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Smart Array CONTROLLER FAILURE at &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Cache Status: OK'&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Notify&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Smart Array CACHE FAILURE at &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;status&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Battery/Capacitor Status: OK'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Notify&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Smart Array BATTERY FAILURE at &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;hpacucli&lt;span class="w"&gt; &lt;/span&gt;ctrl&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$SLOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;array&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ARRAY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;show&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-q&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Status: OK'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Notify&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Smart Array ARRAY FAILURE at &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# This is for testing:
#Notify &amp;quot;This is a test&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;For other hardware health checks I wrote this one and put it in &lt;em&gt;/usr/local/sbin/hw_health_check&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="ch"&gt;#!/bin/sh
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;EMAIL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# You can put your e-mail address here
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c1"&gt;# This function is called if checks don't pass
&lt;/span&gt;Notify&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c1"&gt;# Something went wrong. Send e-mail
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;SUBJECT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$SUBJECT&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Check&lt;span class="w"&gt; &lt;/span&gt;date:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;date&lt;span class="w"&gt; &lt;/span&gt;+&lt;span class="s2"&gt;&amp;quot;%F %T%:::z&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'== Power Supply Status =='&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'== System Fan Status =='&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'== Temperatures =='&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'== HP System Log =='&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mail&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$SUBJECT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$EMAIL&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Power supply check with hplog -p:
#
# ID     TYPE        LOCATION      STATUS  REDUNDANT
#  1  Standard     Pwr. Supply Bay Normal     No
#  2  Standard     Pwr. Supply Bay Normal     No
#
# A failed power supply looks like this:
#
# ID     TYPE        LOCATION      STATUS  REDUNDANT
#  1  Standard     Pwr. Supply Bay Normal     No
#  2  Standard     Pwr. Supply Bay Failed     No
#
# A removed power supply looks like this:
#
# ID     TYPE        LOCATION      STATUS  REDUNDANT
#  1  Standard     Pwr. Supply Bay Normal     No
#  2  Standard     Pwr. Supply Bay Absent     No
#
# The total number of power supplies should equal the number of
# power supplies with the status &amp;quot;Normal&amp;quot;
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;TOTAL_PSU_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;+2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;wc&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;OK_PSU_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;+2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;Normal&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$TOTAL_PSU_COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$OK_PSU_COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;Notify&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SYSTEM POWER SUPPLY PROBLEM at &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Fan check with hplog -f:
#
# ID     TYPE        LOCATION      STATUS  REDUNDANT FAN SPEED
#  1  Var. Speed   I/O Zone        Normal     Yes     Medium ( 45)
#  2  Var. Speed   I/O Zone        Normal     Yes     Medium ( 45)
#  3  Var. Speed   Processor Zone  Normal     Yes     Medium ( 41)
#  4  Var. Speed   Processor Zone  Normal     Yes     Low    ( 36)
#  5  Var. Speed   Processor Zone  Normal     Yes     Low    ( 36)
#  6  Var. Speed   Processor Zone  Normal     Yes     Low    ( 36)
#
# The total number of fans should equal the number of
# fans with the status &amp;quot;Normal&amp;quot;
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;TOTAL_FAN_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;+2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;wc&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;OK_FAN_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;+2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;Normal&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$TOTAL_FAN_COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$OK_FAN_COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;Notify&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SYSTEM FAN PROBLEM at &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Temperature check with hplog -t:
#
# ID     TYPE        LOCATION      STATUS    CURRENT  THRESHOLD
#  1  Basic Sensor I/O Zone        Normal   105F/ 41C 158F/ 70C
#  2  Basic Sensor Ambient         Normal    69F/ 21C 102F/ 39C
#  3  Basic Sensor CPU (1)         Normal    86F/ 30C 260F/127C
#  4  Basic Sensor CPU (1)         Normal    86F/ 30C 260F/127C
#  5  Basic Sensor Pwr. Supply Bay Normal   111F/ 44C 170F/ 77C
#  6  Basic Sensor CPU (2)         Normal    86F/ 30C 260F/127C
#  7  Basic Sensor CPU (2)         Normal    86F/ 30C 260F/127C
#
# The total number of temperature readings should equal the number of
# temperature readings with the status &amp;quot;Normal&amp;quot;
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;TOTAL_TEMP_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;+2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;wc&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;OK_TEMP_COUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hplog&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;+2&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;head&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;-1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;Normal&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$TOTAL_TEMP_COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;!&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$OK_TEMP_COUNT&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;Notify&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;SYSTEM TEMPERATURE PROBLEM at &lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;hostname&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# This is for testing:
#Notify &amp;quot;This is a test&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Add both scripts to crontab with &amp;quot;crontab -e&amp;quot;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
0 0,6,18,12 * * * smart_array_check
0 0,6,18,12 * * * hw_health_check
&lt;/pre&gt;
&lt;p&gt;That will run the checks four times a day and e-mail every time there is a failure.&lt;/p&gt;
&lt;p&gt;Links:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="%20http://downloads.linux.hp.com/downloads/ManagementComponentPack/"&gt;HP Software Delivery Repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Postfix"></category><category term="ProLiant"></category><category term="Ubuntu"></category></entry><entry><title>HP iLO2 Virtual Serial Console on Ubuntu</title><link href="https://mikko.kortelainen.io/blog/hp-ilo2-virtual-serial-console/" rel="alternate"></link><published>2013-03-07T23:54:00+02:00</published><updated>2013-03-07T23:54:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-07:/blog/hp-ilo2-virtual-serial-console/</id><summary type="html">&lt;p&gt;To get a virtual serial console, you need to enable the iLO virtual serial port. I had mine set up like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;iLO 2 Virtual Serial Port: COM2 0x2F8 IRQ 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also enabled ssh access in the iLO web interface. This way I can ssh into the iLO and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;To get a virtual serial console, you need to enable the iLO virtual serial port. I had mine set up like this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;iLO 2 Virtual Serial Port: COM2 0x2F8 IRQ 3&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I also enabled ssh access in the iLO web interface. This way I can ssh into the iLO and see all BIOS messages using the &amp;quot;vsp&amp;quot; command. I can even go to the BIOS setup (RBSU) by pressing &amp;quot;ESC-9&amp;quot;.&lt;/p&gt;
&lt;p&gt;To be able to control GRUB via the virtual serial port, it has to be configured. I changed the following lines in &lt;em&gt;/etc/default/grub&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nv"&gt;GRUB_HIDDEN_TIMEOUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;GRUB_HIDDEN_TIMEOUT_QUIET&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;GRUB_TIMEOUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;GRUB_CMDLINE_LINUX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;text console=tty0 console=ttyS1,115200n8&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;GRUB_TERMINAL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;console
&lt;/pre&gt;
&lt;p&gt;You must run &amp;quot;update-grub&amp;quot; after editing that file to generate the boot configuration.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;GRUB_HIDDEN_TIMEOUT&lt;/em&gt; is the number of seconds to wait for ESC before booting the default kernel. You can press ESC and select another kernel using the virtual serial console.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;GRUB_HIDDEN_TIMEOUT_QUIET=false&lt;/em&gt; shows a countdown, so you know when exactly to press ESC.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;GRUB_CMDLINE_LINUX&lt;/em&gt; directs Linux kernel messages to both console (tty0) and serial port COM2 (ttyS1). You can configure the speed (115200) in the iLO setup.&lt;/p&gt;
&lt;p&gt;To get a login prompt after boot, I added a file named &lt;em&gt;/etc/init/ttyS1.conf&lt;/em&gt; with the following contents:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="c1"&gt;# ttyS1 - getty
#
# This service maintains a getty on tty1 from the point the system is
# started until it is shut down again.
&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;stopped&lt;span class="w"&gt; &lt;/span&gt;rc&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;RUNLEVEL&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="m"&gt;2345&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;not-container&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt;
            &lt;/span&gt;container&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CONTAINER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lxc&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt;
            &lt;/span&gt;container&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;CONTAINER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;lxc-libvirt&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;stop&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;runlevel&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;!2345&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;respawn&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/sbin/getty&lt;span class="w"&gt; &lt;/span&gt;-8&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;115200&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;ttyS1
&lt;/pre&gt;
&lt;p&gt;That will start a getty on the virtual serial port.&lt;/p&gt;
&lt;p&gt;Now I can log in via the iLO if I mess up the network configuration. I can also perform salvage operations at boot time in case filesystem checks fail.&lt;/p&gt;
&lt;p&gt;This has been tested on Ubuntu Server 12.04.2 LTS x86_64.&lt;/p&gt;
</content><category term="Blog"></category><category term="ProLiant"></category><category term="Ubuntu"></category></entry><entry><title>Upgrading HP Proliant iLO2 Firmware with Ubuntu Server</title><link href="https://mikko.kortelainen.io/blog/upgrading-hp-proliant-ilo2-firmware-with-ubuntu-server/" rel="alternate"></link><published>2013-03-07T23:01:00+02:00</published><updated>2013-03-07T23:01:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-03-07:/blog/upgrading-hp-proliant-ilo2-firmware-with-ubuntu-server/</id><summary type="html">&lt;p&gt;I downloaded the firmware from HP site. It was named &lt;em&gt;CP019022.scexe&lt;/em&gt;. I tried
uploading it in the iLO2 web interface, but it was rejected. Next, I copied it
to the server, gave it execute permissions and ran it:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;./CP019022.scexe&lt;span class="w"&gt;
&lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;153&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;pushd:&lt;span class="w"&gt; &lt;/span&gt;not …&lt;/pre&gt;</summary><content type="html">&lt;p&gt;I downloaded the firmware from HP site. It was named &lt;em&gt;CP019022.scexe&lt;/em&gt;. I tried
uploading it in the iLO2 web interface, but it was rejected. Next, I copied it
to the server, gave it execute permissions and ran it:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;./CP019022.scexe&lt;span class="w"&gt;
&lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;153&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;pushd:&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;found&lt;span class="w"&gt;
&lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;158&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;popd:&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;found&lt;span class="w"&gt;
&lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;96&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;./CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;./flash_ilo2:&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;found
&lt;/pre&gt;
&lt;p&gt;Not working. This is a fresh installation of Ubuntu Server 12.04.2 LTS x86_64.
So I had to start looking closer. The file is a bash script but the hashbang is
#!/bin/sh, which puts bash into old Bourne shell mode. No pushd/popd
there.Second try with bash proper:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;bash&lt;span class="w"&gt; &lt;/span&gt;CP019022.scexe&lt;span class="w"&gt;
&lt;/span&gt;CP019022.scexe:&lt;span class="w"&gt; &lt;/span&gt;line&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;96&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;./flash_ilo2:&lt;span class="w"&gt; &lt;/span&gt;No&lt;span class="w"&gt; &lt;/span&gt;such&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;directory
&lt;/pre&gt;
&lt;p&gt;Still not working. Looking at the code, after the script comes a gzipped binary
blob, which seems to be a tar archive. This is unpacked by the script before the
blob. The lines to discard before binary starts are in this variable:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
_SKIP=347
&lt;/pre&gt;
&lt;p&gt;Let's decompress it:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;tail&lt;span class="w"&gt; &lt;/span&gt;-n&lt;span class="w"&gt; &lt;/span&gt;+347&lt;span class="w"&gt; &lt;/span&gt;CP019022.scexe&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;gunzip&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;cp019022.tar
&lt;/pre&gt;
&lt;p&gt;Then take a look at the contents:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;tar&lt;span class="w"&gt; &lt;/span&gt;tvf&lt;span class="w"&gt; &lt;/span&gt;cp019022.tar&lt;span class="w"&gt;
&lt;/span&gt;-rw-rw-rw-&lt;span class="w"&gt; &lt;/span&gt;root/root&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="m"&gt;322387&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2013&lt;/span&gt;-01-18&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:36&lt;span class="w"&gt; &lt;/span&gt;CP019022.xml&lt;span class="w"&gt;
&lt;/span&gt;-rwxr-xr-x&lt;span class="w"&gt; &lt;/span&gt;root/root&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="m"&gt;76812&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2009&lt;/span&gt;-09-01&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;:46&lt;span class="w"&gt; &lt;/span&gt;flash_ilo2&lt;span class="w"&gt;
&lt;/span&gt;-rw-r-xr-x&lt;span class="w"&gt; &lt;/span&gt;root/root&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="m"&gt;3145728&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2013&lt;/span&gt;-01-17&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;23&lt;/span&gt;:03&lt;span class="w"&gt; &lt;/span&gt;ilo2_215.bin&lt;span class="w"&gt;
&lt;/span&gt;-rw-r-xr-x&lt;span class="w"&gt; &lt;/span&gt;root/root&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;5565&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2013&lt;/span&gt;-01-18&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;16&lt;/span&gt;:20&lt;span class="w"&gt; &lt;/span&gt;README.TXT
&lt;/pre&gt;
&lt;p&gt;There's the &amp;quot;flash_ilo2&amp;quot; tool and the &amp;quot;ilo2_215.bin&amp;quot; file which seems to be the
actual firmware. Unpack archive:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;cp019022&lt;span class="w"&gt;
&lt;/span&gt;root&amp;#64;host:~#&lt;span class="w"&gt; &lt;/span&gt;tar&lt;span class="w"&gt; &lt;/span&gt;xvf&lt;span class="w"&gt; &lt;/span&gt;cp019022.tar&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;cp019022&lt;span class="w"&gt;
&lt;/span&gt;CP019022.xml&lt;span class="w"&gt;
&lt;/span&gt;flash_ilo2&lt;span class="w"&gt;
&lt;/span&gt;ilo2_215.bin&lt;span class="w"&gt;
&lt;/span&gt;README.TXT
&lt;/pre&gt;
&lt;p&gt;The readme file says you could actually take the .bin file and use the web
interface to upgrade using that. So that's one possibility.&lt;/p&gt;
&lt;p&gt;Trying the &lt;em&gt;flash_ilo2&lt;/em&gt; command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;host:~/cp019022# ./flash_ilo2
./flash_ilo2: No such file or directory
&lt;/pre&gt;
&lt;p&gt;Doesn't seem to run. Examine the file a bit further:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;host:~/cp019022# file flash_ilo2
flash_ilo2: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.2.5, stripped
&lt;/pre&gt;
&lt;p&gt;So it is a 32-bit executable. Ubuntu server has no 32-bit ELF loader installed
by default. That can be fixed with:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~/cp019022#&lt;span class="w"&gt; &lt;/span&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;libc6-i386
&lt;/pre&gt;
&lt;p&gt;And:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
root&amp;#64;host:~/cp019022#&lt;span class="w"&gt; &lt;/span&gt;./flash_ilo2&lt;span class="w"&gt;

&lt;/span&gt;FLASH_iLO2&lt;span class="w"&gt; &lt;/span&gt;v1.12&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Linux&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;Aug&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;31&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2009&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;Copyright&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2009&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Hewlett-Packard&lt;span class="w"&gt; &lt;/span&gt;Development&lt;span class="w"&gt; &lt;/span&gt;Company,&lt;span class="w"&gt; &lt;/span&gt;L.P.&lt;span class="w"&gt;
&lt;/span&gt;Firmware&lt;span class="w"&gt; &lt;/span&gt;image:&lt;span class="w"&gt; &lt;/span&gt;ilo2_215.bin&lt;span class="w"&gt;
&lt;/span&gt;Current&lt;span class="w"&gt; &lt;/span&gt;iLO&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;firmware&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.05&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Serial&lt;span class="w"&gt; &lt;/span&gt;number&lt;span class="w"&gt; &lt;/span&gt;ILOCZC7402XR0&lt;span class="w"&gt;

&lt;/span&gt;Component&lt;span class="w"&gt; &lt;/span&gt;XML&lt;span class="w"&gt; &lt;/span&gt;file:&lt;span class="w"&gt; &lt;/span&gt;CP019022.xml&lt;span class="w"&gt;
&lt;/span&gt;CP019022.xml&lt;span class="w"&gt; &lt;/span&gt;reports&lt;span class="w"&gt; &lt;/span&gt;firmware&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.15&lt;span class="w"&gt;
&lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;operation&lt;span class="w"&gt; &lt;/span&gt;will&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;firmware&lt;span class="w"&gt; &lt;/span&gt;on&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt;
&lt;/span&gt;iLO&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;server&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;version&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.15.&lt;span class="w"&gt;
&lt;/span&gt;Continue&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;y/N&lt;span class="o"&gt;)&lt;/span&gt;?
&lt;/pre&gt;
&lt;p&gt;It works! So seems like the easy fix is installing 32-bit libc. The original
.scexe seems to work as well, although there are a couple of error messages.&lt;/p&gt;
</content><category term="Blog"></category><category term="ProLiant"></category><category term="Ubuntu"></category><category term="Uncategorized"></category></entry><entry><title>Automount Anything over SSH</title><link href="https://mikko.kortelainen.io/blog/automount-anything-over-ssh/" rel="alternate"></link><published>2013-02-21T12:08:00+02:00</published><updated>2013-02-21T12:08:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-02-21:/blog/automount-anything-over-ssh/</id><summary type="html">&lt;p&gt;First, make sure you can use &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/openssh-public-key-authentication/"&gt;public key authentication&lt;/a&gt; or similar means to connect to ssh servers without typing in your password all the time.&lt;/p&gt;
&lt;p&gt;Install &lt;a class="reference external" href="http://fuse.sourceforge.net/sshfs.html"&gt;sshfs&lt;/a&gt; for mounting remote filesystems over ssh, and &lt;a class="reference external" href="https://github.com/pcarrier/afuse"&gt;afuse&lt;/a&gt; for automounting &lt;a class="reference external" href="http://fuse.sourceforge.net/"&gt;FUSE&lt;/a&gt; filesystems (sshfs uses fuse).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo apt-get install sshfs afuse
&lt;/pre&gt;
&lt;p&gt;For dead connection …&lt;/p&gt;</summary><content type="html">&lt;p&gt;First, make sure you can use &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/openssh-public-key-authentication/"&gt;public key authentication&lt;/a&gt; or similar means to connect to ssh servers without typing in your password all the time.&lt;/p&gt;
&lt;p&gt;Install &lt;a class="reference external" href="http://fuse.sourceforge.net/sshfs.html"&gt;sshfs&lt;/a&gt; for mounting remote filesystems over ssh, and &lt;a class="reference external" href="https://github.com/pcarrier/afuse"&gt;afuse&lt;/a&gt; for automounting &lt;a class="reference external" href="http://fuse.sourceforge.net/"&gt;FUSE&lt;/a&gt; filesystems (sshfs uses fuse).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo apt-get install sshfs afuse
&lt;/pre&gt;
&lt;p&gt;For dead connection detection, add this to your ~/.ssh/config:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Host *
ServerAliveInterval 30
&lt;/pre&gt;
&lt;p&gt;That will ping the remote server every 30 seconds and detect a dead peer. This is needed for the sshfs reconnect option to work properly.&lt;/p&gt;
&lt;p&gt;Create a directory where to automount your remote filesystems:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkdir ~/sshfs
&lt;/pre&gt;
&lt;p&gt;Now ask afuse to automount any server you ask for under that directory:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
afuse -o mount_template='sshfs -o reconnect %r:/ %m' \
      -o unmount_template='fusermount -u -z %m' \
      ~/sshfs/
&lt;/pre&gt;
&lt;p&gt;Now, go to the sshfs directory and cd to some server you know you can log on to:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cd sshfs
cd www.example.com
&lt;/pre&gt;
&lt;p&gt;If your authentication to www.example.com works, you should now be able to list the root directory there.&lt;/p&gt;
&lt;p&gt;Add that afuse command to somewhere where it will be executed when you log in, like &lt;em&gt;~/.xsession&lt;/em&gt;, and you're done. Or use the &lt;em&gt;gnome-session-properties&lt;/em&gt; tool or similar.&lt;/p&gt;
&lt;p&gt;This should work for other FUSE filesystems, but I haven't yet tested them.&lt;/p&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="OpenSSH"></category><category term="Ubuntu"></category></entry><entry><title>Web Messaging with RabbitMQ-Web-Stomp and SockJS</title><link href="https://mikko.kortelainen.io/blog/web-messaging-with-rabbitmq-web-stomp-and-sockjs/" rel="alternate"></link><published>2013-02-18T23:17:00+02:00</published><updated>2013-02-18T23:17:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-02-18:/blog/web-messaging-with-rabbitmq-web-stomp-and-sockjs/</id><summary type="html">&lt;p&gt;In this article, I will discuss sending messages from server to web browser
using &lt;a class="reference external" href="http://www.rabbitmq.com/web-stomp.html"&gt;RabbitMQ-Web-Stomp&lt;/a&gt; as the
backend, and a simple JavaScript library to handle the web browser side. SockJS
is used as the browser WebSockets library. This setup enables you to directly
push messages in realtime from the RabbitMQ …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In this article, I will discuss sending messages from server to web browser
using &lt;a class="reference external" href="http://www.rabbitmq.com/web-stomp.html"&gt;RabbitMQ-Web-Stomp&lt;/a&gt; as the
backend, and a simple JavaScript library to handle the web browser side. SockJS
is used as the browser WebSockets library. This setup enables you to directly
push messages in realtime from the RabbitMQ message broker to the web client.
This makes it possible to deliver status updates to multiple web clients
directly from the message broker. No need for special application server
software in the middle.&lt;/p&gt;
&lt;p&gt;The reverse is also possible. You can push messages from web browsers directly
into the RabbitMQ routing system. This article, though, will discuss the former
case, from server to client. The infrastructure required for the latter case is
the same, with nothing extra needed.&lt;/p&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="auto-toc simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#what-s-needed" id="toc-entry-1"&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;What's Needed&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#rabbitmq-installation" id="toc-entry-2"&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;RabbitMQ Installation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#web-management-plugin-and-the-rabbitmqadmin-script" id="toc-entry-3"&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;Web Management Plugin and the rabbitmqadmin script&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#writing-programs-with-amqp" id="toc-entry-4"&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Writing Programs with AMQP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#messaging-in-a-web-browser-using-rabbitmq-web-stomp" id="toc-entry-5"&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Messaging in a Web Browser using RabbitMQ-Web-Stomp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#a-simple-example" id="toc-entry-6"&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;A simple example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-publisher-in-python" id="toc-entry-7"&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;The publisher in Python&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-consumer-in-javascript" id="toc-entry-8"&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;The Consumer in JavaScript&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#test-it" id="toc-entry-9"&gt;9&amp;nbsp;&amp;nbsp;&amp;nbsp;Test It&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#useful-links" id="toc-entry-10"&gt;10&amp;nbsp;&amp;nbsp;&amp;nbsp;Useful links:&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="what-s-needed"&gt;
&lt;h2&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;What's Needed&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.rabbitmq.com"&gt;RabbitMQ&lt;/a&gt; is a piece of server software which
implements the AMQP messaging standard. Simply put, it maintains a number of
queues for holding incoming messages, and enables other software to publish
messages to those queues, and fetch messages from the queues. There are API
libraries for all major programming languages, including C, Python, Java, Ruby,
PHP and, of course, Erlang, because RabbitMQ itself is written in it.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol"&gt;AMQP&lt;/a&gt; is an
open standard for messaging middleware. In theory, AMQP products from various
vendors should be compatible. AMQP is a binary line protocol, which makes it
fast, but unsuitable for web apps.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://stomp.github.com/"&gt;STOMP&lt;/a&gt; is the Simple (or Streaming) Text
Orientated Messaging Protocol. The RabbitMQ-Web-Stomp plugin can deliver
messages to/from web clients using Stomp.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://jmesnil.net/stomp-websocket/doc/"&gt;The Stomp over Web Socket&lt;/a&gt; library
allows running STOMP streams over web sockets.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="https://github.com/sockjs/sockjs-client"&gt;SockJS&lt;/a&gt; is a
&lt;a class="reference external" href="http://en.wikipedia.org/wiki/WebSocket"&gt;WebSocket&lt;/a&gt;
emulation library which gives a
consistent API on all browser platforms, including some older ones which have
partial or vendor-specific support. Native web sockets are used if the browser
supports them.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="rabbitmq-installation"&gt;
&lt;h2&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;RabbitMQ Installation&lt;/h2&gt;
&lt;p&gt;Here's the &lt;a class="reference external" href="http://www.rabbitmq.com/download.html"&gt;RabbitMQ download page&lt;/a&gt;.
The stuff discussed here has been tested with the package version 3.0.2 on
Ubuntu, which is not yet in the official repositories.&lt;/p&gt;
&lt;p&gt;After installation, you can use the &lt;em&gt;rabbitmqctl&lt;/em&gt; command to command the server.
It will require root privileges.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="web-management-plugin-and-the-rabbitmqadmin-script"&gt;
&lt;h2&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;Web Management Plugin and the rabbitmqadmin script&lt;/h2&gt;
&lt;p&gt;After installing the package, enable the management plugin:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo rabbitmq-plugins enable rabbitmq_management
&lt;/pre&gt;
&lt;p&gt;And restart:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo /etc/init.d/rabbitmq-server restart
&lt;/pre&gt;
&lt;p&gt;The management plugin provides a web interface for configuring the server. By
default it runs at port 15762 (eg. &lt;a class="reference external" href="http://localhost:15672/"&gt;http://localhost:15672/&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;The default username is &lt;em&gt;&amp;quot;guest&amp;quot;&lt;/em&gt; and the password is &lt;em&gt;&amp;quot;guest&amp;quot;&lt;/em&gt;. You should
obviously change these. It can be done using the web admin interface.&lt;/p&gt;
&lt;p&gt;You can download the &lt;em&gt;rabbitmqadmin&lt;/em&gt; Python script from
&lt;a class="reference external" href="http://localhost:15672/cli/"&gt;http://localhost:15672/cli/&lt;/a&gt; . You can control RabbitMQ with this script without
root privileges, if you provide a username and password either on the command
line or in &lt;em&gt;~/.rabbitmqadmin.conf&lt;/em&gt; (run &amp;quot;&lt;em&gt;rabbitmqdamin help configuration&amp;quot;&lt;/em&gt; for
instructions).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="writing-programs-with-amqp"&gt;
&lt;h2&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Writing Programs with AMQP&lt;/h2&gt;
&lt;p&gt;Here are some very nice tutorials on how to write programs for RabbitMQ:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.rabbitmq.com/getstarted.html"&gt;http://www.rabbitmq.com/getstarted.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;We will be using the same pattern as
&lt;a class="reference external" href="http://www.rabbitmq.com/tutorials/tutorial-five-python.html"&gt;example number 5&lt;/a&gt;.
But we will use a web client as the consumer.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="messaging-in-a-web-browser-using-rabbitmq-web-stomp"&gt;
&lt;h2&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;Messaging in a Web Browser using RabbitMQ-Web-Stomp&lt;/h2&gt;
&lt;p&gt;The RabbitMQ-Web-Stomp plugin allows web browsers to do messaging using SockJS.
This will enable a web browser to keep a connection with the message broker, and
receive messages as soon as they appear in the queue. A callback function will
be fired every time upon the receival of a message.&lt;/p&gt;
&lt;p&gt;Install the Web Stomp plugin:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo rabbitmq-plugins enable rabbitmq_web_stomp
&lt;/pre&gt;
&lt;p&gt;Restart RabbitMQ. You should now get a hello page in port 15674 (note the
different port number), under /stomp (&lt;a class="reference external" href="http://localhost:15674/stomp"&gt;http://localhost:15674/stomp&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;(If you install the rabbitmq_web_stomp_examples plugin as well, you can find
examples at &lt;a class="reference external" href="http://localhost:15670/"&gt;http://localhost:15670/&lt;/a&gt;. You can download the stomp.js file used in
my example from &lt;a class="reference external" href="http://localhost:15670/web-stomp-examples/stomp.js"&gt;http://localhost:15670/web-stomp-examples/stomp.js&lt;/a&gt;)&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="a-simple-example"&gt;
&lt;h2&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;A simple example&lt;/h2&gt;
&lt;p&gt;To demonstrate a simple use case, let's write two programs. The first one is a
Python program for publishing messages, and the other one is a web app for
reading those messages.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-publisher-in-python"&gt;
&lt;h2&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;The publisher in Python&lt;/h2&gt;
&lt;p&gt;This one will use the &lt;a class="reference external" href="https://github.com/pika/pika/"&gt;Pika&lt;/a&gt; AMQP client
library (&lt;em&gt;sudo apt-get install python-pika&lt;/em&gt;, or &lt;em&gt;pip install pika)&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Let's call this app &lt;em&gt;publisher.py&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="ch"&gt;#!/usr/bin/python&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;pika&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Use plain credentials for authentication&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;mq_creds&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PlainCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;guest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;guest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Use localhost&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;mq_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ConnectionParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;host&lt;/span&gt;         &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;localhost&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;credentials&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mq_creds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="n"&gt;virtual_host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# Anyone subscribing to topic &amp;quot;mymessages&amp;quot; receives our messages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;mq_exchange&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;amq.topic&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;mq_routing_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;mymessages&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# This a connection object&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;mq_conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pika&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BlockingConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mq_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;# This is one channel inside the connection&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;mq_chan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mq_conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;channel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;readline&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Press Ctrl+C to quit.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;raw_input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Enter your message: &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Sending '&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;'&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;mq_chan&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;basic_publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;exchange&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mq_exchange&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;routing_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mq_routing_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;      &lt;span class="n"&gt;body&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;That will simply prompt the user for a line of text, and publish it to the
&lt;em&gt;amq.topic&lt;/em&gt; exchange of the default virtualhost &lt;em&gt;&amp;quot;/&amp;quot;&lt;/em&gt;, using routing key
&lt;em&gt;mymessages&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Run the script with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
python publisher.py
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="the-consumer-in-javascript"&gt;
&lt;h2&gt;8&amp;nbsp;&amp;nbsp;&amp;nbsp;The Consumer in JavaScript&lt;/h2&gt;
&lt;p&gt;Here's an example app which can read messages using SockJS. Let's call it
&lt;em&gt;listener-app.html.&lt;/em&gt;&lt;/p&gt;
&lt;pre class="code html literal-block"&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;content-type&amp;quot;&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text/html; charset=utf-8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Testing RabbitMQ Web Stomp&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;title&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!-- From: http://cdn.sockjs.org/ --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;sockjs-0.3.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!-- From RabbitMQ-Web-Stomp examples --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;stomp.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="cm"&gt;&amp;lt;!-- Our example app --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;listener-app.js&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;solid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;black&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="k"&gt;min-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;style&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;head&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Waiting for messages&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;output&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="cm"&gt;&amp;lt;!-- incoming messages will be printed here --&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Here's &lt;em&gt;listener-app.js&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code js literal-block"&gt;
&lt;span class="c1"&gt;// Use SockJS&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nx"&gt;Stomp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WebSocketClass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;SockJS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// Connection parameters&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;mq_username&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;guest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;mq_password&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;guest&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;mq_vhost&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;mq_url&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'http://'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;':15674/stomp'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="c1"&gt;// The queue we will read. The /topic/ queues are temporary&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;// queues that will be created when the client connects, and&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;// removed when the client disconnects. They will receive&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;// all messages published in the &amp;quot;amq.topic&amp;quot; exchange, with the&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="c1"&gt;// given routing key, in this case &amp;quot;mymessages&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;mq_queue&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/topic/mymessages&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// This is where we print incomoing messages&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// This will be called upon successful connection&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;on_connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Connected to RabbitMQ-Web-Stomp&amp;lt;br /&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mq_queue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;on_message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// This will be called upon a connection error&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;on_connect_error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'Connection failed!&amp;lt;br /&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// This will be called upon arrival of a message&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;on_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'message received'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'&amp;lt;br /&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c1"&gt;// Create a client&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Stomp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mq_url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c1"&gt;// Fetch output panel&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;output&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;output&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c1"&gt;// Connect&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;mq_username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;mq_password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;on_connect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;on_connect_error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nx"&gt;mq_vhost&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;You will also need the &lt;em&gt;sockjs-0.3.js&lt;/em&gt; and&amp;nbsp;&lt;em&gt;stomp.js&lt;/em&gt; files. I will include them
in this post.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="test-it"&gt;
&lt;h2&gt;9&amp;nbsp;&amp;nbsp;&amp;nbsp;Test It&lt;/h2&gt;
&lt;p&gt;If you now point your browser to
&lt;a class="reference external" href="http://localhost/rabbitmq-web-stomp-example/listener-app.html"&gt;http://localhost/rabbitmq-web-stomp-example/listener-app.html&lt;/a&gt;, you should see a
text saying &amp;quot;Connected to RabbitMQ-Web-Stomp&amp;quot;.&lt;/p&gt;
&lt;p&gt;Now, write a message in the terminal window running the &lt;em&gt;publish.py&lt;/em&gt; Python
script. It should appear in the browser window immediately.&lt;/p&gt;
&lt;p&gt;You can open multiple browser windows, and they should all get the message. You
can also open multiple publisher scripts at once.&lt;/p&gt;
&lt;p&gt;At this point, you should see some connections, channels and queues appear in
the RabbitMQ web management interface. There should be one of each for every
browser window and running Python script.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="useful-links"&gt;
&lt;h2&gt;10&amp;nbsp;&amp;nbsp;&amp;nbsp;Useful links:&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.rabbitmq.com/blog/2012/05/14/introducing-rabbitmq-web-stomp/"&gt;http://www.rabbitmq.com/blog/2012/05/14/introducing-rabbitmq-web-stomp/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.rabbitmq.com/web-stomp.html"&gt;http://www.rabbitmq.com/web-stomp.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.rabbitmq.com/stomp.html"&gt;http://www.rabbitmq.com/stomp.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://github.com/sockjs/sockjs-client"&gt;https://github.com/sockjs/sockjs-client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://jmesnil.net/stomp-websocket/doc/"&gt;http://jmesnil.net/stomp-websocket/doc/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here's the example, unpack it under you web server's document root:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/files/rabbitmq-web-stomp-example.tar.gz"&gt;rabbitmq-web-stomp-example.tar&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="JavaScript"></category><category term="Messaging"></category><category term="Python"></category><category term="RabbitMQ"></category></entry><entry><title>Command-T - Fast file navigation for VIM</title><link href="https://mikko.kortelainen.io/blog/command-t-fast-file-navigation-for-vim/" rel="alternate"></link><published>2013-02-13T15:51:00+02:00</published><updated>2013-02-13T15:51:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-02-13:/blog/command-t-fast-file-navigation-for-vim/</id><summary type="html">&lt;p&gt;Ingenious, fast way to find your files:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.vim.org/scripts/script.php?script_id=3025"&gt;Command-T - Fast file navigation for VIM : vim online&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I use the following mappings:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
&amp;quot; Set leader key to comma
let mapleader = &amp;quot;,&amp;quot;

&amp;quot; Command-T shortcuts
nnoremap &amp;lt;silent&amp;gt; &amp;lt;Leader&amp;gt;t :CommandT&amp;lt;CR&amp;gt;
nnoremap &amp;lt;silent&amp;gt; &amp;lt;Leader&amp;gt;b :CommandTBuffer&amp;lt;CR&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Bring up the finder with &lt;strong&gt;,t&lt;/strong&gt; or &amp;quot;comma-t&amp;quot;. Use …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ingenious, fast way to find your files:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.vim.org/scripts/script.php?script_id=3025"&gt;Command-T - Fast file navigation for VIM : vim online&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I use the following mappings:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
&amp;quot; Set leader key to comma
let mapleader = &amp;quot;,&amp;quot;

&amp;quot; Command-T shortcuts
nnoremap &amp;lt;silent&amp;gt; &amp;lt;Leader&amp;gt;t :CommandT&amp;lt;CR&amp;gt;
nnoremap &amp;lt;silent&amp;gt; &amp;lt;Leader&amp;gt;b :CommandTBuffer&amp;lt;CR&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Bring up the finder with &lt;strong&gt;,t&lt;/strong&gt; or &amp;quot;comma-t&amp;quot;. Use the &lt;em&gt;:CommandTFlush&lt;/em&gt; command to re-read directory.&lt;/p&gt;
</content><category term="Blog"></category><category term="Vim"></category></entry><entry><title>Temporarily Disable PostgreSQL Triggers</title><link href="https://mikko.kortelainen.io/blog/disable-postgresql-triggers-temporarily/" rel="alternate"></link><published>2013-01-08T11:05:00+02:00</published><updated>2013-01-08T11:05:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-01-08:/blog/disable-postgresql-triggers-temporarily/</id><summary type="html">&lt;p&gt;To temporarily disable &lt;strong&gt;all&lt;/strong&gt; triggers in a PostgreSQL session, use this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
SET session_replication_role = replica;
&lt;/pre&gt;
&lt;p&gt;That disables all triggers for the current database session only. Useful for bulk operations, but remember to be careful to keep your database consistent.&lt;/p&gt;
&lt;p&gt;To re-enable:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
SET session_replication_role = DEFAULT;
&lt;/pre&gt;
&lt;div class="section" id="disable-a-single-trigger"&gt;
&lt;h2&gt;Disable a Single Trigger&lt;/h2&gt;
&lt;p&gt;To disable just …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;To temporarily disable &lt;strong&gt;all&lt;/strong&gt; triggers in a PostgreSQL session, use this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
SET session_replication_role = replica;
&lt;/pre&gt;
&lt;p&gt;That disables all triggers for the current database session only. Useful for bulk operations, but remember to be careful to keep your database consistent.&lt;/p&gt;
&lt;p&gt;To re-enable:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
SET session_replication_role = DEFAULT;
&lt;/pre&gt;
&lt;div class="section" id="disable-a-single-trigger"&gt;
&lt;h2&gt;Disable a Single Trigger&lt;/h2&gt;
&lt;p&gt;To disable just a single trigger, use ALTER TABLE:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ALTER TABLE mytable DISABLE TRIGGER mytrigger;
&lt;/pre&gt;
&lt;p&gt;The difference to the previous method is that ALTER TABLE will globally disable the trigger, affecting all database sessions, not just the current one.&lt;/p&gt;
&lt;p&gt;To disable all triggers for one table:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ALTER TABLE mytable DISABLE TRIGGER ALL;
&lt;/pre&gt;
&lt;p&gt;To re-enable:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ALTER TABLE mytable ENABLE TRIGGER ALL;
&lt;/pre&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="PostgreSQL"></category></entry><entry><title>Ubuntu 12.04 Active Directory Authentication</title><link href="https://mikko.kortelainen.io/blog/ubuntu-12-04-active-directory-authentication/" rel="alternate"></link><published>2013-01-06T14:07:00+02:00</published><updated>2013-01-06T14:07:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-01-06:/blog/ubuntu-12-04-active-directory-authentication/</id><summary type="html">&lt;p&gt;&lt;em&gt;Update 2015-06-16:&lt;/em&gt;&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/ubuntu-14-04-active-directory-authentication/"&gt;Ubuntu 14.04 Active Directory Authentication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Authenticating Linux users against Active Directory has traditionally been hard.
There's a multitude of HOWTOs on how to do it, and every one of them seems to do
it a bit differently. This is because environments and goals vary, and there are …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;Update 2015-06-16:&lt;/em&gt;&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/ubuntu-14-04-active-directory-authentication/"&gt;Ubuntu 14.04 Active Directory Authentication&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Authenticating Linux users against Active Directory has traditionally been hard.
There's a multitude of HOWTOs on how to do it, and every one of them seems to do
it a bit differently. This is because environments and goals vary, and there are
many ways to achieve a particular goal. I will add my version to the mix. This
one fetches users and groups from Active Directory LDAP using a machine account
added using the Samba tools, and authenticates users to the Active Directory Key
Distribution Center using Kerberos.&lt;/p&gt;
&lt;p&gt;I will use the LDAP schema that comes with the Microsoft Services for Unix Tools
which has later been renamed to Subsystem for UNIX-based Applications (SUA).&lt;/p&gt;
&lt;p&gt;I will configure the server to fetch user account and group data from Active
Directory LDAP using the &lt;em&gt;nss_ldap&lt;/em&gt; Name Service Switch module. This information
will be used in addition to the data found in local &lt;em&gt;/etc/passwd&lt;/em&gt; and
&lt;em&gt;/etc/group&lt;/em&gt; files. I will also configure the Kerberos authentication client
using MIT Kerberos libraries and tools, and configure the &lt;em&gt;pam_ldap&lt;/em&gt; Pluggable
Authentication Module to utilize it. The Samba tools are used to add a machine
account for the host, as well as a keytab file which will be used for querying
Active Directory LDAP. No need to add special user accounts for querying AD.&lt;/p&gt;
&lt;p&gt;Still, the whole process is not simple by any means. Here's an outline:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Install and configure the MIT Kerberos client and test that it works&lt;/li&gt;
&lt;li&gt;Install and configure the Samba tools&lt;/li&gt;
&lt;li&gt;Use the Samba tools to &amp;quot;join&amp;quot; the machine to the domain, or in other words, to create a machine account for it in the AD LDAP&lt;/li&gt;
&lt;li&gt;Add forward and reverse DNS records for the machine&lt;/li&gt;
&lt;li&gt;Create the host keytab file&lt;/li&gt;
&lt;li&gt;Map a suitable Kerberos principal to the new machine account in AD, and test that it works with the keytab file&lt;/li&gt;
&lt;li&gt;Make sure there's a valid ticket for the machine account all the time&lt;/li&gt;
&lt;li&gt;Extend AD LDAP schema using the SFU/SUA tools&lt;/li&gt;
&lt;li&gt;Install LDAP tools and test connecting to the AD and see the internal structure&lt;/li&gt;
&lt;li&gt;Install and configure nss_ldap to fetch user and group information from AD&lt;/li&gt;
&lt;li&gt;Install and configure pam_ldap to authenticate to AD&lt;/li&gt;
&lt;li&gt;Add a PAM directive to create a home directory for a user logging in the first time if such a directory does not yet exist&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="contents topic" id="table-of-contents"&gt;
&lt;p class="topic-title"&gt;Table of Contents&lt;/p&gt;
&lt;ul class="auto-toc simple"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#install-and-configure-kerberos" id="toc-entry-1"&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Install and configure kerberos&lt;/a&gt;&lt;ul class="auto-toc"&gt;
&lt;li&gt;&lt;a class="reference internal" href="#configure-samba" id="toc-entry-2"&gt;1.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Configure Samba&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#join-to-domain" id="toc-entry-3"&gt;1.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Join to Domain&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#create-a-keytab-file" id="toc-entry-4"&gt;1.3&amp;nbsp;&amp;nbsp;&amp;nbsp;Create a Keytab file&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#make-sure-there-s-a-valid-machine-account-ticket-all-the-time" id="toc-entry-5"&gt;1.4&amp;nbsp;&amp;nbsp;&amp;nbsp;Make Sure There's a Valid Machine Account Ticket all the time&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#install-openldap-tools" id="toc-entry-6"&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Install OpenLDAP tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-active-directory-schema" id="toc-entry-7"&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;The Active Directory Schema&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#install-and-configure-nss-ldap-and-pam-ldap" id="toc-entry-8"&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Install and configure nss_ldap and pam_ldap&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#pam-configuration" id="toc-entry-9"&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;PAM configuration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#the-end-result" id="toc-entry-10"&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;The End Result&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference internal" href="#useful-links" id="toc-entry-11"&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Useful links&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class="section" id="install-and-configure-kerberos"&gt;
&lt;h2&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp;Install and configure kerberos&lt;/h2&gt;
&lt;p&gt;Install the Kerberos library, related PAM library, and also Samba client which
we will just use to create a machine account in the domain, and create a keytab
file.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo aptitude install libpam-krb5 krb5-user smbclient
&lt;/pre&gt;
&lt;p&gt;Type in your AD Kerberos realm when prompted. It should generally be your domain
name in capital letters (&amp;quot;koo.fi&amp;quot; becomes &amp;quot;KOO.FI&amp;quot;). If your DNS is working
properly, that should be all that is needed for Kerberos client to work in a
basic manner. Otherwise you may need to add your servers to &lt;em&gt;/etc/krb5.conf&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Try getting a ticket:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# kinit Administrator&amp;#64;KOO.FI
Password for Administrator&amp;#64;KOO.FI:
# klist

Ticket cache: FILE:/tmp/krb5cc_0
Default principal: Administrator&amp;#64;KOO.FI

Valid starting     Expires            Service principal
06/09/11 12:01:22  06/09/11 22:01:06  krbtgt/KOO.FI&amp;#64;KOO.FI
    renew until 06/10/11 12:01:22
&lt;/pre&gt;
&lt;p&gt;That shows we now have a valid ticket and the Kerberos authentication is working
fine to the domain controller.&lt;/p&gt;
&lt;p&gt;Some extra configuration at this point in krb5.conf. The &lt;em&gt;appdefaults/pam&lt;/em&gt;
configuration section is where &lt;em&gt;pam_krb5&lt;/em&gt; module gets its configuration from
(see for example &lt;a class="reference external" href="http://linux.die.net/man/5/pam_krb5"&gt;http://linux.die.net/man/5/pam_krb5&lt;/a&gt;).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[appdefaults]
pam = {
        realm = KOO.FI
        ticket_lifetime = 1d
        renew_lifetime = 1d
        forwardable = true
        proxiable = false
        retain_after_close = false
        minimum_uid = 2
        try_first_pass = true
        ignore_root = true
}
[libdefaults]
        default_realm = KOO.FI
        default_keytab_name = FILE:/etc/krb5.keytab
        default_tkt_enctypes = rc4-hmac des-cbc-crc des-cbc-md5
        default_tgs_enctypes = rc4-hmac des-cbc-crc des-cbc-md5

[realms]
        KOO.FI = {
                auth_to_local = DEFAULT
        }
[domain_realm]
        .koo.fi = KOO.FI
        koo.fi = KOO.FI
&lt;/pre&gt;
&lt;p&gt;The auth_to_local rule will try to parse the local username from the Kerberos
principal name, otherwise it will use the principal name itself (see
&lt;a class="reference external" href="http://linux.die.net/man/5/krb5.conf"&gt;http://linux.die.net/man/5/krb5.conf&lt;/a&gt;).&lt;/p&gt;
&lt;div class="section" id="configure-samba"&gt;
&lt;h3&gt;1.1&amp;nbsp;&amp;nbsp;&amp;nbsp;Configure Samba&lt;/h3&gt;
&lt;p&gt;We only need the Samba client because it is a convenient tool to create a
machine account in Active Directory. Configure Samba client using
&lt;em&gt;/etc/samba/smb.conf&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[global]
  netbios name = UBUNTU
  realm = KOO.FI
  workgroup = KOO
  security = ADS
  kerberos method = system keytab
&lt;/pre&gt;
&lt;p&gt;The &amp;quot;system keytab&amp;quot; kerberos method states that the Kerberos system is used to
find the keytab file
&lt;a class="reference external" href="http://www.samba.org/samba/docs/man/manpages-3/smb.conf.5.html#KERBEROSMETHOD"&gt;(see http://www.samba.org/samba/docs/man/manpages-3/smb.conf.5.html#KERBEROSMETHOD&lt;/a&gt;).
We defined it in &lt;em&gt;krb5.conf&lt;/em&gt; above.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="join-to-domain"&gt;
&lt;h3&gt;1.2&amp;nbsp;&amp;nbsp;&amp;nbsp;Join to Domain&lt;/h3&gt;
&lt;p&gt;Join the machine to the domain. This command creates a machine account in AD:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# sudo net ads join -U Administrator
Enter Administrator's password:
Using short domain name -- KOO
Joined 'UBUNTU' to realm 'koo.fi'
DNS update failed!
&lt;/pre&gt;
&lt;p&gt;If you get the &amp;quot;DNS update failed&amp;quot; error message, you just need to create a host
record in DNS manually (both forward and reverse).&lt;/p&gt;
&lt;p&gt;After this, you should basicly be able to remove smbclient should you wish to do
so. I didn't bother.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="create-a-keytab-file"&gt;
&lt;h3&gt;1.3&amp;nbsp;&amp;nbsp;&amp;nbsp;Create a Keytab file&lt;/h3&gt;
&lt;p&gt;A keytab file should automatically be created by net ads join as
&lt;em&gt;/etc/krb5.keytab&lt;/em&gt;. This was stated earlier in &lt;em&gt;krb5.conf.&lt;/em&gt; You can also create
the keytab file manually with the following command (from the smbclient
package):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# sudo net ads keytab create
&lt;/pre&gt;
&lt;p&gt;Test the keytab with this command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# sudo kinit -V -k 'UBUNTU$'
Authenticated to Kerberos v5
&lt;/pre&gt;
&lt;p&gt;That means you are able to authenticate with the keytab file using principal
UBUNTU$. If you have error messages, you may turn on debug output in krb5.conf:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[logging]
    default = SYSLOG:DEBUG
&lt;/pre&gt;
&lt;p&gt;The next step is to go to your Active Directory domain controller and use the
ktpass.exe tool to create a host principal (&amp;quot;host/ubuntu.koo.fi&amp;quot;) and map it to
the machine account that was created (&amp;quot;UBUNTU$&amp;quot;).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
C:\Users\Administrator.KOO&amp;gt;ktpass /princ &amp;quot;host/ubuntu.koo.fi&amp;#64;KOO.FI&amp;quot; /mapuser UBUNTU$&amp;#64;KOO.FI
Targeting domain controller: DC1.koo.fi
Using legacy password setting method
Successfully mapped host/ubuntu.koo.fi to ubuntu$.
&lt;/pre&gt;
&lt;p&gt;Now you should be able to run:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="c1"&gt;# sudo kinit -V -k 'host/ubuntu.koo.fi&amp;#64;KOO.FI'
&lt;/span&gt;Using&lt;span class="w"&gt; &lt;/span&gt;default&lt;span class="w"&gt; &lt;/span&gt;cache:&lt;span class="w"&gt; &lt;/span&gt;/tmp/krb5cc_0&lt;span class="w"&gt;
&lt;/span&gt;Using&lt;span class="w"&gt; &lt;/span&gt;principal:&lt;span class="w"&gt; &lt;/span&gt;host/ubuntu.koo.fi&amp;#64;KOO.FI&lt;span class="w"&gt;
&lt;/span&gt;Authenticated&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;Kerberos&lt;span class="w"&gt; &lt;/span&gt;v5
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="make-sure-there-s-a-valid-machine-account-ticket-all-the-time"&gt;
&lt;h3&gt;1.4&amp;nbsp;&amp;nbsp;&amp;nbsp;Make Sure There's a Valid Machine Account Ticket all the time&lt;/h3&gt;
&lt;p&gt;Now that we have a working keytab file, we'll have to make sure we have a valid
ticket all the time, and that it can be accessed by every user who needs it.
Active Directory has a maximum ticket lifetime of 10 hours. The keytab file by
itself will not be enough to authenticate, but it can be used to get a ticket
from a KDC. We can do it with a cron job (&amp;quot;sudo crontab -e&amp;quot;):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
0 * * * * kinit -k ‘host/ubuntu.koo.fi&amp;#64;KOO.FI’ -c /tmp/krb5cc_host; chmod +r /tmp/krb5cc_host
&lt;/pre&gt;
&lt;p&gt;That will run kinit every hour as root, and save the host credentials in the
Kerberos credentials cache file &lt;em&gt;/etc/krb5cc_host&lt;/em&gt;. This file contains the live
tickets, and needs to be refreshed periodically. It also needs to be readable by
all users who need to read information from the LDAP directory. That is why we
add world-readable permissions to it.&lt;/p&gt;
&lt;p&gt;Security-wise, it is important to remember, that anyone who has read permissions
to the credentials cache can pose as the principal whose keys are in the file.
In our case, it is the AD machine account. You may wish to restrict who has
access to the file using groups or acls. You could revoke access from
nobody:nogroup like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
0 * * * * kinit -k ‘host/ubuntu.koo.fi&amp;#64;KOO.FI’ -c /tmp/krb5cc_host; chmod +r /tmp/krb5cc_host; setfacl -m u:nobody:--- /tmp/krb5cc_host; setfacl -m g:nogroup:--- /tmp/krb5cc_host
&lt;/pre&gt;
&lt;p&gt;All that has to be on one line in the crontab. Or you could create a shell
script for it. You also need to install the &amp;quot;acl&amp;quot; package to get the &lt;em&gt;setfacl&lt;/em&gt;
command.&lt;/p&gt;
&lt;p&gt;To see what credentials are currently in the file, run:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="c1"&gt;# klist -c /tmp/krb5cc_host&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="install-openldap-tools"&gt;
&lt;h2&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;Install OpenLDAP tools&lt;/h2&gt;
&lt;p&gt;While not strictly necessary, it is helpful at this point to test authentication
to AD and fetching stuff from it, usind &lt;em&gt;ldap-utils&lt;/em&gt; and SASL module:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# sudo aptitude install ldap-utils libsasl2-modules-gssapi-mit
&lt;/pre&gt;
&lt;p&gt;Edit &lt;em&gt;/etc/ldap/ldap.conf&lt;/em&gt; (the OpenLDAP tools configuration file) and put your
own details there:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
BASE   dc=koo,dc=fi
URI ldap://dc1.koo.fi ldap://dc2.koo.fi
&lt;/pre&gt;
&lt;p&gt;Now, after fetching a ticket with the command &amp;quot;kinit &lt;a class="reference external" href="mailto:username&amp;#64;REALM"&gt;username&amp;#64;REALM&lt;/a&gt;&amp;quot; you should
be able to run plain &amp;quot;ldapsearch&amp;quot; and see the contents of your whole Active
Directory (or up to about a thousand entries) using that Kerberos ticket. This
will turn out handy in the next section.&lt;/p&gt;
&lt;p&gt;You should also be able to authenticate using the principal in your keytab file
at this point. Destroy your ticket by running &lt;em&gt;kdestroy&lt;/em&gt;. After fetching a
ticket with the keytab file by running &lt;em&gt;kinit -V -k
'host/ubuntu.koo.fi&amp;#64;KOO.FI',&lt;/em&gt; you should also be able to ldapsearch without
problems.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-active-directory-schema"&gt;
&lt;h2&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp;The Active Directory Schema&lt;/h2&gt;
&lt;p&gt;The Active Directory LDAP Schema must be extended by installing the Microsoft
Services For Unix on an Active Directory Domain controller. The schema extension
adds some extra attributes to the directory that allow you to specify user's ID
number, home directory, shell etc. You can edit them in a new tab which should
appear in the &lt;em&gt;Active Directory Users and Computers&lt;/em&gt; snap-in. It looks something
like this:&lt;/p&gt;
&lt;p&gt;The attribute names and objectclasses used in the following discussion have been
taken from my setup. They may vary depending on which MS SFU version you have
installed at the moment, or which version you installed the first time. It is
therefore advisable to take a look at your own directory and take the correct
attribute names from there. To do that, go to &lt;em&gt;AD Users and Computers&lt;/em&gt;, add
&lt;em&gt;UNIX attributes&lt;/em&gt; for one user with UNIX attributes set up, and also one such
group, and then run &lt;em&gt;ldapsearch&lt;/em&gt; to see the attributes:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# ldapsearch &amp;quot;(cn=Mikko K. Kortelainen)&amp;quot;
&lt;/pre&gt;
&lt;p&gt;That whill search by the username and should return a list of attributes saved
for the user. My attributes look like this (I removed a lot of stuff from here,
only relevant attrs showed):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# Mikko K. Kortelainen, Unix, koo.fi
dn: CN=Mikko K. Kortelainen,OU=Unix,DC=koo,DC=fi
cn: Mikko K. Kortelainen
name: Mikko K. Kortelainen
pwdLastSet: 129520857664062022
uid: mikko
uidNumber: 10385
gidNumber: 10019
loginShell: /bin/bash
name: Mikko K. Kortelainen
msSFU30Password:
unixHomeDirectory: /home/user/mikko
msSFU30PosixMemberOf: CN=UNIX users,OU=Unix,DC=koo,DC=fi
&lt;/pre&gt;
&lt;p&gt;Let's look at the group &amp;quot;UNIX users&amp;quot;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# ldapsearch &amp;quot;(cn=UNIX users)&amp;quot;

dn: CN=UNIX users,OU=Unix,DC=koo,DC=fi
cn: UNIX users
msSFU30PosixMember:: ...
msSFU30PosixMember:: ...
msSFU30PosixMember:: ...
msSFU30PosixMember:: ...
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;msSFU30PosixMember&lt;/em&gt; attributes contain references to the member user
accounts. That will be used to map users to groups.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="install-and-configure-nss-ldap-and-pam-ldap"&gt;
&lt;h2&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp;Install and configure nss_ldap and pam_ldap&lt;/h2&gt;
&lt;p&gt;Now, let's install nss_ldap (the name service switch ldap module) and pam_ldap
(the PAM ldap module):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# sudo aptitude install libnss-ldap libpam-ldap
&lt;/pre&gt;
&lt;p&gt;Dpkg will ask questions to do some preconfiguring. This configuration will use
the Kerberos host keytab:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
LDAP server: ldap://dc1.koo.fi ldap://dc2.koo.fi
Distinguished name of the search base: dc=koo,dc=fi
LDAP version to use: 3
Make local root database admin: no
Does the database require login: no
Password hash: md5
&lt;/pre&gt;
&lt;p&gt;Next, let's configure &lt;em&gt;/etc/ldap.conf&lt;/em&gt; some more. This configuration file is for
both the pam_ldap and nss_ldap. You will need to substitute your own values
here. Let's go through it piece by piece.&lt;/p&gt;
&lt;p&gt;First some basic information on how to connect to the directory, and timeouts,
option to not to be fussy over SSL/TLS certificates and to ignore referrals. If
your directory is partitioned you will have to enable referrals. In that case be
sure to have connectivity to all domain controllers, as well as a working DNS.
The &lt;em&gt;use_sasl on&lt;/em&gt; option will change to using Kerberos through SASL. The
&lt;em&gt;sasl_auth_id&lt;/em&gt; must be the same which you mapped to your machine account with
the &lt;em&gt;ktpass&lt;/em&gt; Windows command earlier.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;krb5_ccname&lt;/em&gt; tells where to find the Kerberos credentials cache file.&amp;nbsp; The
file must be readable by any user you wish to be able to read information from
AD. It must also be refreshed periodically. This was configured as a cron job
earlier in this article.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
use_sasl on
sasl_auth_id host/ubuntu.koo.fi
krb5_ccname FILE:/tmp/krb5cc_host
base dc=koo,dc=fi
uri ldap://dc1.koo.fi ldap://dc2.koo.fi
ldap_version 3
timelimit 30
bind_timelimit 30
tls_checkpeer no
referrals no
bind_policy soft
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;nss_base_ attributes&lt;/em&gt; tell where to look for particular types of objects
in the directory. We will simply give the root object with subtree scope so that
the whole directory is checked. You may want to restrict this for performance
reasons if you have a huge directory, or for security reasons if you have strict
permissions in your directory.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
scope sub
nss_base_passwd dc=koo,dc=fi?sub
nss_base_shadow dc=koo,dc=fi?sub
nss_base_group dc=koo,dc=fi?sub
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;nss_map_attribute&lt;/em&gt; is used to map an ldap attribute to a Linux NSS
property. The first argument is the NSS property, and the second argument is the
LDAP attribute from which to fetch the value. Be sure to double-check the
attribute names that they match the ones in your directory.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
nss_map_objectclass posixAccount User
nss_map_objectclass shadowAccount User
nss_map_attribute uid uid
nss_map_attribute uidNumber uidNumber
nss_map_attribute gidNumber gidNumber
nss_map_attribute loginShell loginShell
nss_map_attribute gecos name
nss_map_attribute userPassword msSFU30Password
nss_map_attribute homeDirectory unixHomeDirectory
nss_map_attribute shadowLastChange pwdLastSet
nss_map_objectclass posixGroup Group
nss_map_attribute uniqueMember msSFU30PosixMember
nss_map_attribute cn cn
nss_initgroups_ignoreusers backup,bin,clamav,daemon,dovecot,dspam,games,gnats,irc,landscape,libuuid,list,lp,mail,man,messagebus,mysql,nagios,news,ntp,openamq,postfix,postgres,proxy,rabbitmq,root,sshd,statd,sync,sys,syslog,uucp,www-data
&lt;/pre&gt;
&lt;p&gt;The &lt;em&gt;pam_login_attribute&lt;/em&gt; is used as the user name for the PAM authentication
process. The &lt;em&gt;pam_password&lt;/em&gt; says which kind of a protocol to use for changing
user passwords if that is needed. You need to install &lt;em&gt;libpam-ldap&lt;/em&gt; to take
advantage of it.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
pam_login_attribute msSFU30Name
pam_filter objectclass=user
pam_password ad
&lt;/pre&gt;
&lt;p&gt;The last change is needed to the file &lt;em&gt;/etc/nsswitch.conf&lt;/em&gt; so that the Name
Service Switch knows it should be querying AD:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
passwd: compat ldap
group: compat ldap
shadow: compat ldap
&lt;/pre&gt;
&lt;p&gt;Only those three lines need editing.&lt;/p&gt;
&lt;p&gt;At this stage, you should be able to list users from Active Directory using
&amp;quot;getent passwd&amp;quot;, and groups using &amp;quot;getent group&amp;quot;. If you can't, add line &amp;quot;debug
1&amp;quot; to &lt;em&gt;/etc/ldap.conf&lt;/em&gt; and try re-running &amp;quot;getent passwd&amp;quot;. It should give you a
pretty verbose log of what's going on. You can set the verbosity up to 10 if you
like.&lt;/p&gt;
&lt;p&gt;If you want to cache the results, you can install the &amp;quot;unscd&amp;quot; package. That will
cache users and groups, so that they are not asked from LDAP every time, which
makes things faster. You can tune the settings in &lt;em&gt;/etc/nscd.conf&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pam-configuration"&gt;
&lt;h2&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;PAM configuration&lt;/h2&gt;
&lt;p&gt;Now that the NSS part is working properly, let's configure PAM. It should mostly
be done automatically already, just double-check it.&lt;/p&gt;
&lt;p&gt;This is what my &lt;em&gt;/etc/pam.d/common-auth&lt;/em&gt; looks like:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
auth   [success=3 default=ignore]  pam_krb5.so minimum_uid=1000
auth    [success=2 default=ignore]  pam_unix.so nullok_secure try_first_pass
auth    [success=1 default=ignore]  pam_ldap.so use_first_pass
auth    requisite           pam_deny.so
auth    required            pam_permit.so
&lt;/pre&gt;
&lt;p&gt;That will enable Kerberos, LDAP and Unix passwd file authentication.&lt;/p&gt;
&lt;p&gt;This is &lt;em&gt;/etc/pam.d/common-account:&lt;/em&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
account    [success=2 new_authtok_reqd=done default=ignore]    pam_unix.so
account [success=1 default=ignore]  pam_ldap.so
account requisite           pam_deny.so
account required            pam_permit.so
account required            pam_krb5.so minimum_uid=1000
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;/etc/pam.d/common-password:&lt;/em&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
password   requisite           pam_krb5.so minimum_uid=1000
password    [success=2 default=ignore]  pam_unix.so obscure use_authtok try_first_pass sha512
password    [success=1 user_unknown=ignore default=die] pam_ldap.so use_authtok try_first_pass
password    requisite           pam_deny.so
password    required            pam_permit.so
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;/etc/pam.d/common-session:&lt;/em&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
session [default=1] pam_permit.so
session requisite  pam_deny.so
session required   pam_permit.so
session optional   pam_umask.so
session optional   pam_krb5.so minimum_uid=1000
session required   pam_unix.so
session required   pam_mkhomedir.so skel=/etc/skel/ umask=0077
session optional   pam_ldap.so
session optional&amp;nbsp;&amp;nbsp; pam_ck_connector.so nox11
&lt;/pre&gt;
&lt;p&gt;The only thing I had to change was to add the &lt;em&gt;pam_mkhomedir.so&lt;/em&gt; line, which
creates a home directory automatically for any user logging in the first time.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-end-result"&gt;
&lt;h2&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp;The End Result&lt;/h2&gt;
&lt;p&gt;After all that is in place, you should be able to log in locally, or remotely
with &lt;em&gt;ssh&lt;/em&gt;, using a user account from AD, authenticating to AD with Kerberos,
and get your home directory created automatically for you should it not exist
already.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="useful-links"&gt;
&lt;h2&gt;7&amp;nbsp;&amp;nbsp;&amp;nbsp;Useful links&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://publib.boulder.ibm.com/iseries/v5r1/ic2924/info/rzakh/rzakha06.htm"&gt;Kerberos protocol concepts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="https://help.ubuntu.com/community/Kerberos"&gt;Kerberos - Community Ubuntu Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/5/nss_ldap"&gt;nss_ldap(5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/5/pam_ldap"&gt;pam_ldap(5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/5/pam_krb5"&gt;pam_krb5(5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://linux.die.net/man/5/nscd.conf"&gt;nscd.conf(5)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.samba.org/samba/docs/man/manpages-3/smb.conf.5.html#KERBEROSMETHOD"&gt;smb.conf - kerberos method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://kb.iu.edu/data/aumh.html"&gt;What is a keytab, and how do I use one?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Active Directory"></category><category term="Kerberos"></category><category term="Samba"></category><category term="Ubuntu"></category></entry><entry><title>Checking PostgreSQL Disk Usage</title><link href="https://mikko.kortelainen.io/blog/checking-postgresql-disk-usage/" rel="alternate"></link><published>2013-01-06T09:36:00+02:00</published><updated>2013-01-06T09:36:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2013-01-06:/blog/checking-postgresql-disk-usage/</id><summary type="html">&lt;p&gt;This query sums total disk space used by the table including indexes and toasted data for the 20 largest tables:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nspname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;relname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s-Name"&gt;&amp;quot;relation&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_total_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s-Name"&gt;&amp;quot;total_size&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relnamespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nspname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pg_catalog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'information_schema'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;AND …&lt;/span&gt;&lt;/pre&gt;</summary><content type="html">&lt;p&gt;This query sums total disk space used by the table including indexes and toasted data for the 20 largest tables:&lt;/p&gt;
&lt;pre class="code postgres literal-block"&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nspname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'.'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;||&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;relname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s-Name"&gt;&amp;quot;relation&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;pg_size_pretty&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pg_total_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s-Name"&gt;&amp;quot;total_size&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;LEFT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;JOIN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relnamespace&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;WHERE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nspname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;NOT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;IN&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'pg_catalog'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'information_schema'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;relkind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'i'&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="k"&gt;AND&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nspname&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!~&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'^pg_toast'&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;ORDER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;BY&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pg_total_relation_size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="n"&gt;oid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DESC&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;LIMIT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;via &lt;a class="reference external" href="http://wiki.postgresql.org/wiki/Disk_Usage"&gt;Disk Usage - PostgreSQL wiki&lt;/a&gt;.&lt;/p&gt;
</content><category term="Blog"></category><category term="PostgreSQL"></category></entry><entry><title>Apache HTTP authentication against WordPress password database</title><link href="https://mikko.kortelainen.io/blog/apache-http-authentication-against-wordpress-password-database/" rel="alternate"></link><published>2012-12-19T18:24:00+02:00</published><updated>2012-12-19T18:24:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-12-19:/blog/apache-http-authentication-against-wordpress-password-database/</id><summary type="html">&lt;p&gt;The stock &lt;a class="reference external" href="http://modauthmysql.sourceforge.net/"&gt;mod_auth_mysql&lt;/a&gt; package in Ubuntu is not able to authenticate against the &lt;a class="reference external" href="http://www.openwall.com/phpass/"&gt;phpass&lt;/a&gt; password hashes stored in the WordPress database.&lt;/p&gt;
&lt;p&gt;There seems to be a &lt;a class="reference external" href="http://pelam.fi/published_sources/mod-auth-mysql-phpass/patch.diff"&gt;patch&lt;/a&gt; lying around to enable phpass authentication in mod_auth_mysql. Its inclusion in mod_auth_mysql has been &lt;a class="reference external" href="http://sourceforge.net/projects/modauthmysql/forums/forum/202942/topic/3812112"&gt;requested&lt;/a&gt; a long time ago, and &lt;a class="reference external" href="http://sourceforge.net/tracker/?func=detail&amp;amp;aid=3572669&amp;amp;group_id=60218&amp;amp;atid=493464"&gt;again more recently …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;The stock &lt;a class="reference external" href="http://modauthmysql.sourceforge.net/"&gt;mod_auth_mysql&lt;/a&gt; package in Ubuntu is not able to authenticate against the &lt;a class="reference external" href="http://www.openwall.com/phpass/"&gt;phpass&lt;/a&gt; password hashes stored in the WordPress database.&lt;/p&gt;
&lt;p&gt;There seems to be a &lt;a class="reference external" href="http://pelam.fi/published_sources/mod-auth-mysql-phpass/patch.diff"&gt;patch&lt;/a&gt; lying around to enable phpass authentication in mod_auth_mysql. Its inclusion in mod_auth_mysql has been &lt;a class="reference external" href="http://sourceforge.net/projects/modauthmysql/forums/forum/202942/topic/3812112"&gt;requested&lt;/a&gt; a long time ago, and &lt;a class="reference external" href="http://sourceforge.net/tracker/?func=detail&amp;amp;aid=3572669&amp;amp;group_id=60218&amp;amp;atid=493464"&gt;again more recently&lt;/a&gt;, but for one reason or another it has been declined.&amp;nbsp;Inclusion of the patch into the Debian package has also been &lt;a class="reference external" href="http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=689014"&gt;requested&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks to Peter Lamberg, there are &lt;a class="reference external" href="http://stackoverflow.com/questions/12543883/apache-mod-auth-mysql-with-phpass-encrypted-password-wordpress"&gt;good instructions&lt;/a&gt; around on how to apply the patch and enable it. I've made available a pre-compiled 64-bit package here:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/files/libapache2-mod-auth-mysql_4.3.9-13ubuntu3_amd64.deb"&gt;libapache2-mod-auth-mysql_4.3.9-13ubuntu3_amd64&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Below are the instructions to compile one from scratch, and after it follows an example configuration.&lt;/p&gt;
&lt;p&gt;Please remember, it is always a good practice to use SSL/TLS protection when sending user authentication information over the Internet.&lt;/p&gt;
&lt;div class="section" id="compiling-a-patched-package-in-ubuntu-12-04"&gt;
&lt;h2&gt;Compiling a Patched Package in Ubuntu 12.04&lt;/h2&gt;
&lt;p&gt;Make a working directory:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
mkdir&lt;span class="w"&gt; &lt;/span&gt;mod-auth-mysql-phpass&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mod-auth-mysql-phpass
&lt;/pre&gt;
&lt;p&gt;Get the dependencies and source code for mod_auth_mysql:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;build-dep&lt;span class="w"&gt; &lt;/span&gt;mod-auth-mysql&lt;span class="w"&gt;
&lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mod-auth-mysql
&lt;/pre&gt;
&lt;p&gt;Also install fakeroot for the patching to be successful:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;fakeroot
&lt;/pre&gt;
&lt;p&gt;Go to the source code:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;mod-auth-mysql-4.3.9
&lt;/pre&gt;
&lt;p&gt;Check patch list:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cat debian/patches/00list
&lt;/pre&gt;
&lt;p&gt;Add a new patch with the last patch in the list as the base (for me it was number 17):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
dpatch-edit-patch patch 018-phpass 017-doc_persistent_conn.dpatch
&lt;/pre&gt;
&lt;p&gt;It should print something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
dpatch-edit-patch:

Now launching an interactive shell in your work directory. Edit your files.
When you are done, exit the shell. When you exit the shell, your patch will be
automatically updated based on the changes in your work directory.
&lt;/pre&gt;
&lt;p&gt;Download the patch:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
wget&lt;span class="w"&gt; &lt;/span&gt;http://pelam.fi/published_sources/mod-auth-mysql-phpass/patch.diff
&lt;/pre&gt;
&lt;p&gt;Apply patch, then delete it:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
patch&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;&lt;span class="w"&gt; &lt;/span&gt;patch.diff&lt;span class="w"&gt;
&lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;patch.diff
&lt;/pre&gt;
&lt;p&gt;Exit &lt;em&gt;dpatch-edit-patch&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It should print something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
dpatch-edit-patch: /home/user/mod-auth-mysql-phpass/mod-auth-mysql-4.3.9/debian/patches/018-phpass.dpatch created.
&lt;/pre&gt;
&lt;p&gt;Add the new patch to the end of the patch list:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;018&lt;/span&gt;-phpass.dpatch&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;debian/patches/00list
&lt;/pre&gt;
&lt;p&gt;Build the patched version:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
dpkg-buildpackage&lt;span class="w"&gt; &lt;/span&gt;-b&lt;span class="w"&gt; &lt;/span&gt;-uc
&lt;/pre&gt;
&lt;p&gt;The package should appear one level up in the directory tree:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;..
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="installing-the-patched-deb"&gt;
&lt;h2&gt;Installing the Patched .deb&lt;/h2&gt;
&lt;p&gt;Just install:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo dpkg --install libapache2-mod-auth-mysql_4.3.9-13ubuntu3_amd64.deb
&lt;/pre&gt;
&lt;p&gt;And make sure it is not upgraded automatically:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
echo &amp;quot;libapache2-mod-auth-mysql hold&amp;quot; | sudo dpkg --set-selections
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="configuring-the-patched-mod-auth-mysql"&gt;
&lt;h2&gt;Configuring the Patched mod_auth_mysql&lt;/h2&gt;
&lt;p&gt;Enable the module:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;a2enmod&lt;span class="w"&gt; &lt;/span&gt;auth_mysql
&lt;/pre&gt;
&lt;p&gt;Read the documentation:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
less&lt;span class="w"&gt; &lt;/span&gt;/usr/share/doc/libapache2-mod-auth-mysql/DIRECTIVES.gz
&lt;/pre&gt;
&lt;p&gt;Create a directory for protected files:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
mkdir&lt;span class="w"&gt; &lt;/span&gt;/var/www/protected
&lt;/pre&gt;
&lt;p&gt;Configure either using .htaccess file &lt;strong&gt;/var/www/protected/.htaccess&lt;/strong&gt; (you must have &amp;quot;&lt;em&gt;AllowOverride AuthConfig Limit&amp;quot;&lt;/em&gt; enabled for this to work), or directly to Apache configuration:&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="c"&gt;# Disable file-based auth&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;AuthBasicAuthoritative&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;Off&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;AuthUserFile&lt;/span&gt;&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="sx"&gt;/dev/null&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Enable MySQL auth&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;AuthMySQL&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="k"&gt;On&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;AuthType&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;Basic&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;AuthName&lt;/span&gt;&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unauthorized use prohibited&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Basic information - fill in your own details here&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_User&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;DB_USER&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_Password&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;DB_PASSWORD&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_Host&lt;/span&gt;&lt;span class="w"&gt;             &lt;/span&gt;DB_HOST&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_DB&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;DB_NAME&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_CharacterSet&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;utf8&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# The table and fields to use&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_Password_Table&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;wp_users&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_Username_Field&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;wp_users.user_login&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_Password_Field&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;wp_users.user_pass&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Auth_MySQL_Encryption_Types&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;PHPass&lt;span class="w"&gt; &lt;/span&gt;PHP_MD5&lt;span class="w"&gt; &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;This&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;where&lt;span class="w"&gt; &lt;/span&gt;we&lt;span class="w"&gt; &lt;/span&gt;need&lt;span class="w"&gt; &lt;/span&gt;the&lt;span class="w"&gt; &lt;/span&gt;patch&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Any user found in the table can log in&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Require&lt;/span&gt;&lt;span class="w"&gt;                     &lt;/span&gt;valid-user&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Users can log in from anywhere&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Order&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;allow,deny&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Allow&lt;/span&gt;&lt;span class="w"&gt;                       &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Replace the DB* values with values of your own (you can use the same values you have in wp-config.php).&lt;/p&gt;
&lt;p&gt;Add a test file:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;/var/www/protected/test.txt
&lt;/pre&gt;
&lt;p&gt;Restart Apache:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;service&lt;span class="w"&gt; &lt;/span&gt;apache2&lt;span class="w"&gt; &lt;/span&gt;restart
&lt;/pre&gt;
&lt;p&gt;Now you should be prompted for username and password when you try to fetch the test file. Also, you should be able to log in with your WordPress username and password but with nothing else.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="protecting-wordpress-with-http-authentication"&gt;
&lt;h2&gt;Protecting WordPress with http Authentication&lt;/h2&gt;
&lt;p&gt;At first it may sound silly, but you may wish to protect the WordPress installation itself using http authentication. This configuration is useful, if you want each user to only log in once anywhere on your site (inside or outside of WordPress) using http authentication.&lt;/p&gt;
&lt;p&gt;To make WordPress recognize http-authenticated users, install the &lt;a class="reference external" href="http://wordpress.org/extend/plugins/http-authentication/"&gt;HTTP Authentication plugin&lt;/a&gt;&amp;nbsp;to WordPress. Then, enable the plugin. The plugin needs no further configuration. Just protect what you want with Apache directives. You can protect the whole site, or just the &lt;strong&gt;wp-login.php&lt;/strong&gt; file and &lt;strong&gt;wp-admin&lt;/strong&gt; directory to protect logins and administration with http auth.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Apache"></category><category term="mod_auth_*"></category><category term="MySQL"></category><category term="Wordpress"></category></entry><entry><title>Serving Python scripts with Apache mod_wsgi, part II - mod_rewrite</title><link href="https://mikko.kortelainen.io/blog/serving-python-scripts-with-apache-mod_wsgi-part-ii-mod_rewrite/" rel="alternate"></link><published>2012-12-04T07:29:00+02:00</published><updated>2012-12-04T07:29:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-12-04:/blog/serving-python-scripts-with-apache-mod_wsgi-part-ii-mod_rewrite/</id><summary type="html">&lt;p&gt;In &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/serving-python-scripts-with-apache-mod_wsgi-part-i/"&gt;part I&lt;/a&gt;, we learned how to configure Apache to server any .py file as a web application using mod_wsgi. I promised to tell you more about WebOb and multiprocessing and multithreading, and exception handling. I'll save those topics for later articles. Instead, in this part I will talk about …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/serving-python-scripts-with-apache-mod_wsgi-part-i/"&gt;part I&lt;/a&gt;, we learned how to configure Apache to server any .py file as a web application using mod_wsgi. I promised to tell you more about WebOb and multiprocessing and multithreading, and exception handling. I'll save those topics for later articles. Instead, in this part I will talk about using mod_rewrite - if, why and how to get rid of the .py extension. You will need the test apps from part I to try these out.&lt;/p&gt;
&lt;div class="section" id="removing-the-py-extension-using-mod-rewrite"&gt;
&lt;h2&gt;Removing the .py extension using mod_rewrite&lt;/h2&gt;
&lt;p&gt;Many people (including myself) will think that they want to get rid of the .py extension in the URLs. There are valid reasons for this:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;The URLs would be more readable. As we all know it is much easier to remember and understand a URL like &lt;strong&gt;http://localhost/myapp/myfeature&lt;/strong&gt;, than something like &lt;strong&gt;http://localhost/myapp.py?action=myfeature&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The URLs would be more portable. You could, say, re-write your page with C or Haskell, or with whatever you desire, and the users would not notice a thing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also valid reasong speaking against rewriting URLs with mod_rewrite:&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;It might be confusing for the developer, or the application integrator, or the webadmin taking care of the production server. If you have both a script called &lt;strong&gt;myapp.py&lt;/strong&gt; and a directory &lt;strong&gt;myapp&lt;/strong&gt;, which one is going to be called?&lt;/li&gt;
&lt;li&gt;mod_rewrite allows some really nasty tricks in the wrong hands, so for security reasons, it is not a good idea to allow anybody on a shared server to just write their own rules without admin review.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Keeping these things in mind, I'll try to show you how to use mod_rewrite to hide the .py extension. First, enable the rewrite module:&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;a2enmod&lt;span class="w"&gt; &lt;/span&gt;rewrite
&lt;/pre&gt;
&lt;p&gt;Then add this to Apache site configuration (or .htaccess in /var/www if you have &lt;strong&gt;AllowOverride +FileInfo +Options&lt;/strong&gt; set for your dir):&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/www/&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;...&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;options&lt;span class="w"&gt; &lt;/span&gt;...&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+FollowSymLinks&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;RewriteEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%{REQUEST_FILENAME}&lt;span class="w"&gt; &lt;/span&gt;!-d&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%{REQUEST_FILENAME}\.py&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;RewriteRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;^(.*)$&lt;span class="w"&gt; &lt;/span&gt;$1.py&lt;span class="w"&gt; &lt;/span&gt;[L]&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Restart Apache. Now you can browse to &lt;a class="reference external" href="http://localhost/python_app/hello"&gt;http://localhost/python_app/hello&lt;/a&gt; or &lt;a class="reference external" href="http://localhost/python_app/environ"&gt;http://localhost/python_app/environ&lt;/a&gt;. In the latter, observe that the REQUEST_URI variable has no .py extension, while the SCRIPT_NAME still does:&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;REQUEST_URI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/python_app/environ&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SCRIPT_FILENAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/var/www/python_app/environ.py&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SCRIPT_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/python_app/environ.py&lt;/span&gt;
&lt;/pre&gt;
&lt;p class="rubric" id="dissecting-the-rewrite-rules"&gt;Dissecting the rewrite rules&lt;/p&gt;
&lt;p&gt;So what do all those Apache directives do? The first line,&amp;nbsp;&lt;strong&gt;Options +FollowSymLinks&lt;/strong&gt;, is required for rewritten URLs to work, otherwise Apache will deny the requests. The &lt;strong&gt;RewriteEngine on&lt;/strong&gt; directive is needed in order to have any rewriting take place at all. The real magic happens in the last three lines. According to the &lt;a class="reference external" href="http://httpd.apache.org/docs/current/mod/mod_rewrite.html"&gt;documentation&lt;/a&gt;, the &lt;strong&gt;RewriteCond&lt;/strong&gt; directive &amp;quot;Defines a condition under which rewriting will take place&amp;quot;, while the &lt;strong&gt;RewriteRule&lt;/strong&gt; directive &amp;quot;Defines rules for the rewriting engine&amp;quot;. All the conditions preceding the rule must evaluate to true in order for the rule to be followed and the URL be rewritten.&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nb"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%{REQUEST_FILENAME}&lt;span class="w"&gt; &lt;/span&gt;!-d
&lt;/pre&gt;
&lt;p&gt;This states, that the the requested filename (eg. &amp;quot;hello&amp;quot;) must not (!) be an existing directory (-d).&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nb"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;%{REQUEST_FILENAME}\.py&lt;span class="w"&gt; &lt;/span&gt;-f
&lt;/pre&gt;
&lt;p&gt;This states, that the requested file (eg. &amp;quot;hello&amp;quot;) with a .py extension added (&amp;quot;hello.py&amp;quot;) must be an existing file (-f).&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nb"&gt;RewriteRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;^(.*)$&lt;span class="w"&gt; &lt;/span&gt;$1.py&lt;span class="w"&gt; &lt;/span&gt;[L]
&lt;/pre&gt;
&lt;p&gt;If the above two conditions were met, the requested URL (eg. &amp;quot;/python_app/hello&amp;quot;), denoted here with the regular expression &amp;quot;^(.*)$&amp;quot;, should be rewritten with a .py extension (&amp;quot;/python_app/hello.py&amp;quot;). The $1 is a backreference to the regular expression. The final [L] says that processing should stop here. It has no meaning if you don't have any other rules. But when you add more rules, mod_rewrite will continue evaluating them if you don't tell it to stop here.&lt;/p&gt;
&lt;p class="rubric" id="observing-url-dispatch-after-rewriting"&gt;Observing URL dispatch after rewriting&lt;/p&gt;
&lt;p&gt;Now, what happens if we create a directory called &amp;quot;hello&amp;quot; in the python_app directory? There's already a &amp;quot;hello.py&amp;quot; file, which we should be able to request without .py extension due to our new rewrite rules. Let's try what happens:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;/var/www/python_app/hello
&lt;/pre&gt;
&lt;p&gt;Now,&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/hello"&gt;http://localhost/python_app/hello&lt;/a&gt;&amp;nbsp;goes to the directory. Was this expected? Well, yes it is. After all, the first rewrite condition explicitly stated that the requested file must not be an existing directory for any rewriting to take place.&lt;/p&gt;
&lt;p&gt;If you want to have it the other way around, you need to take the first RewriteCond out and do a bit more configuring. If you look closely, Apache actually redirected you to another url with an additional slash at the end (&lt;a class="reference external" href="http://localhost/python_app/hello/"&gt;http://localhost/python_app/hello/&lt;/a&gt;). The &amp;quot;culprit&amp;quot; for the extra slash is &lt;a class="reference external" href="http://httpd.apache.org/docs/2.2/mod/mod_dir.html"&gt;mod_dir&lt;/a&gt; and the DirectorySlash directive, which is on by default. Turning it off and taking out the first RewriteCond will make the url without the slash call the script, and with the slash call the directory. Please note that this might be a security risk, because requesting a directory name without a slash will by default list all files in that directory. So if you have a directory, but no script with the same name, your directory contents can be listed.&lt;/p&gt;
&lt;p&gt;Anyway, I think the latter behaviour is harder to use and understand. And I think that it is a good idea to avoid having same names for directories and scripts. Have apache handle the URL dispatch up to your script, and you handle it from there on in your code.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="docutils container"&gt;
Useful resources:&lt;/div&gt;
&lt;div class="docutils container"&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://httpd.apache.org/docs/current/mod/mod_rewrite.html"&gt;http://httpd.apache.org/docs/current/mod/mod_rewrite.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Apache"></category><category term="mod_dir"></category><category term="mod_rewrite"></category><category term="mod_wsgi"></category><category term="Python"></category></entry><entry><title>Make WordPress Twenty Eleven theme post pages full wide</title><link href="https://mikko.kortelainen.io/blog/make-wordpress-twenty-eleven-theme-post-pages-full-wide/" rel="alternate"></link><published>2012-12-04T03:06:00+02:00</published><updated>2012-12-04T03:06:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-12-04:/blog/make-wordpress-twenty-eleven-theme-post-pages-full-wide/</id><summary type="html">&lt;p&gt;I wanted to make the indivitual post pages 100% wide, and also the headings a
bit bigger. Here's the CSS to do it:&lt;/p&gt;
&lt;pre class="code css literal-block"&gt;
&lt;span class="c"&gt;/* Make individual posts full-width */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;hentry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;em&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-content&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-meta&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;comments-title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;/* Fix the edit button placement */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular …&lt;/span&gt;&lt;/pre&gt;</summary><content type="html">&lt;p&gt;I wanted to make the indivitual post pages 100% wide, and also the headings a
bit bigger. Here's the CSS to do it:&lt;/p&gt;
&lt;pre class="code css literal-block"&gt;
&lt;span class="c"&gt;/* Make individual posts full-width */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;hentry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="kt"&gt;em&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-header&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-content&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-meta&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;#&lt;/span&gt;&lt;span class="nn"&gt;comments-title&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="k"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="kt"&gt;%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;/* Fix the edit button placement */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-meta&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;edit-link&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;/* Make headings a bit bigger */&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;44&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;singular&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;entry-content&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;font-size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="k"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="kt"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;div class="section" id="example-h1"&gt;
&lt;h2&gt;Example H1&lt;/h2&gt;
&lt;p&gt;Example text 1&lt;/p&gt;
&lt;div class="section" id="example-h2"&gt;
&lt;h3&gt;Example H2&lt;/h3&gt;
&lt;p&gt;Example text 2&lt;/p&gt;
&lt;p&gt;I used the Add to All plugin to do it. Seems to work fine.&amp;nbsp;Thanks go to:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wordpress.org/support/topic/twenty-eleven-copy-make-content-wider-for-one-col-layout"&gt;http://wordpress.org/support/topic/twenty-eleven-copy-make-content-wider-for-one-col-layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ajaydsouza.com/wordpress/plugins/add-to-all/"&gt;http://ajaydsouza.com/wordpress/plugins/add-to-all/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Site info"></category><category term="Wordpress"></category></entry><entry><title>AVH First Defense Against Spam « WordPress Plugins</title><link href="https://mikko.kortelainen.io/blog/avh-first-defense-against-spam-wordpress-plugins/" rel="alternate"></link><published>2012-12-02T23:03:00+02:00</published><updated>2012-12-02T23:03:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-12-02:/blog/avh-first-defense-against-spam-wordpress-plugins/</id><summary type="html">&lt;p&gt;I added the AVH First Defence Against Spam plugin to my site. Please report to me If you can't post comments:&lt;/p&gt;
&lt;p&gt;&lt;script type="text/javascript"&gt;// &lt;![CDATA[&lt;br /&gt;
var a = new Array('i','p.f','tec','ain','tel','kor','mik','ko.','en@','hel');document.write("&lt;a href='mailto:"+a[6]+a[7]+a[5]+a …&lt;/script&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;I added the AVH First Defence Against Spam plugin to my site. Please report to me If you can't post comments:&lt;/p&gt;
&lt;p&gt;&lt;script type="text/javascript"&gt;// &lt;![CDATA[&lt;br /&gt;
var a = new Array('i','p.f','tec','ain','tel','kor','mik','ko.','en@','hel');document.write("&lt;a href='mailto:"+a[6]+a[7]+a[5]+a[4]+a[3]+a[8]+a[2]+a[9]+a[1]+a[0]+"'&gt;"+a[6]+a[7]+a[5]+a[4]+a[3]+a[8]+a[2]+a[9]+a[1]+a[0]+"&lt;/a&gt;");&lt;br /&gt;
// ]]&gt;&lt;/script&gt;&lt;/p&gt;&lt;p&gt;&lt;a class="reference external" href="http://wordpress.org/extend/plugins/avh-first-defense-against-spam/"&gt;WordPress › AVH First Defense Against Spam « WordPress Plugins&lt;/a&gt;.&lt;/p&gt;
</content><category term="Blog"></category><category term="Site info"></category></entry><entry><title>Serving Python scripts with Apache mod_wsgi, part I</title><link href="https://mikko.kortelainen.io/blog/serving-python-scripts-with-apache-mod_wsgi-part-i/" rel="alternate"></link><published>2012-12-02T22:53:00+02:00</published><updated>2012-12-02T22:53:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-12-02:/blog/serving-python-scripts-with-apache-mod_wsgi-part-i/</id><summary type="html">&lt;p&gt;I admit it, I'm a long-time PHP programmer. I got stuck with it for a long time
with all my web-based stuff, simply because it is so easy to set up. Well, there
is no set-up, it just works. You just add pages to your web server root and give …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I admit it, I'm a long-time PHP programmer. I got stuck with it for a long time
with all my web-based stuff, simply because it is so easy to set up. Well, there
is no set-up, it just works. You just add pages to your web server root and give
a .php extension to them, and they get requests and give back responses. Nice
and simple.&lt;/p&gt;
&lt;p&gt;I still use PHP for quick and dirty things (like running shell commands through
web interfaces - yes, really, really naughty...) For doing more complex work, I
prefer Python. But I miss the PHP-like way of just adding pages or &amp;quot;web
applications&amp;quot; with zero-setup. I will examine the possibilities in Python for
this kind of behaviour in this article.&lt;/p&gt;
&lt;p&gt;Please remember, there are many, some say even too many, Python&amp;nbsp;web frameworks
available already that handle all this stuff for you &amp;quot;automagically&amp;quot;. You are
almost certainly better off with using one of them, if you want to get work
done. But they all require some kind of setup work.&lt;/p&gt;
&lt;p&gt;Then there's the thing with all kinds of frameworks, that instead of you calling
some library, the behaviour of which you understand, to do your work, a
framework calls your code. That is all right when things work as expected. But
whenever there are glitches, you need to start digging around the framework code
to see exactly what's wrong. And if it is a big framework, that could mean a lot
of digging around. For that reason, if you're a reasonably seasoned programmer,
I think it might not be half bad an idea to create your own minimalistic
framework, using existing, good quality libraries the behaviour of which you
understand, and which you can easily poke in the Python shell if you think
something's not working like it should. Or just to see what's available, and try
out the available code.&lt;/p&gt;
&lt;p&gt;Also, knowing how stuff works never hurts. This article is also about learning
how the Apache http requests are dispatched to Python code through mod_wsgi. I
insist on knowing how things work, so I'm doing it the hard way.&lt;/p&gt;
&lt;div class="section" id="apache-configuration"&gt;
&lt;h2&gt;Apache configuration&lt;/h2&gt;
&lt;p&gt;Now let's get on to the subject matter.&amp;nbsp;First, we must install the
&lt;a class="reference external" href="http://code.google.com/p/modwsgi/"&gt;mod_wsgi&lt;/a&gt; module for Apache.
This is for Python 2.&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;aptitude&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;libapache2-mod-wsgi
&lt;/pre&gt;
&lt;p&gt;There's a module for Python 3 as well in the repos if you wish to use it. I
haven't tested this with Python 3 but it should work if all the modules are
there.&lt;/p&gt;
&lt;p&gt;The following Apache directives will make mod_wsgi handle all requests for files
with a .py extension. You can save it for example into
file&amp;nbsp;&lt;strong&gt;/etc/apache2/mods-enabled/wsgi_script.conf&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nt"&gt;&amp;lt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mod_wsgi.c&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c"&gt;# Handle all .py files with mod_wsgi&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;FilesMatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.+\.py$&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;SetHandler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;wsgi-script&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/FilesMatch&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c"&gt;# Deny access to compiled binaries&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="c"&gt;# You should not serve these to anyone&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;FilesMatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.+\.py(c|o)$&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;Order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Deny,Allow&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;Deny&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/FilesMatch&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Note that any compiled .pyc or .pyo files must be denied explicitly. You don't
want people downloading your compiled code.&lt;/p&gt;
&lt;p&gt;One more thing to configure for Apache: the directory where your scripts are
must have the ExecCGI option set (for example in
&lt;strong&gt;/etc/apache2/sites-enabled/000-default&lt;/strong&gt;):&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/www/&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+ExecCGI&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;This might be a security issue if you have other executable stuff exposed. Now,
after reloading the Apache configuration, of course, we are set to add .py
pages.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="pages-in-mod-wsgi-and-python"&gt;
&lt;h2&gt;Pages in mod_wsgi and Python&lt;/h2&gt;
&lt;p&gt;One thing to note about mod_wsgi is that it will require you to set up a
function (or any callable) which handles the requests. By default, it calls the
function called &amp;quot;&lt;em&gt;application&lt;/em&gt;&amp;quot;, with a couple of parameters. Here's a simple
example. Let's put it in a new directory &lt;strong&gt;/var/www/python_app&lt;/strong&gt; and call it
&lt;strong&gt;hello.py&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'200 OK'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;response_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;'Content-type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;
&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Hello world!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;This is being served using mod_wsgi&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now, point your browser to the hello.py script (for example
&lt;a class="reference external" href="http://localhost/python_app/hello.py"&gt;http://localhost/python_app/hello.py&lt;/a&gt;) and you should see a page.&lt;/p&gt;
&lt;p&gt;As you can see, mod_wsgi passes two arguments to the function &lt;em&gt;application&lt;/em&gt;. The
first contains lots of environment variables from the http request, like
parameters, headers, server and client information, etc.&lt;/p&gt;
&lt;p&gt;The second argument is a function which should be used to start the response. It
takes the http status code and the response headers as arguments. The
start_response function must be called in order to produce something else than
an internal server error to the client.&lt;/p&gt;
&lt;p&gt;The last thing we did here, is construct a simple web page, and return it as the
content.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-mod-wsgi-environment"&gt;
&lt;h2&gt;The mod_wsgi environment&lt;/h2&gt;
&lt;p&gt;Now, let's take a look at the &lt;em&gt;environment&lt;/em&gt; argument. It is probably easiest to
dump it to &lt;a class="reference external" href="http://www.yaml.org/"&gt;YAML&lt;/a&gt;, so let's install the Python module:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
aptitude&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;python-yaml
&lt;/pre&gt;
&lt;p&gt;Add the following application into for example &lt;strong&gt;/var/www/python_app/environ.py&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;yaml&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'200 OK'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;response_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;'Content-type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'text/plain'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;yaml&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And go check what the page (&lt;a class="reference external" href="http://localhost/python_app/environ.py"&gt;http://localhost/python_app/environ.py&lt;/a&gt;) shows you.
There should be a list of environment variables, both from Apache and mod_wsgi.
Something like this:&lt;/p&gt;
&lt;pre class="code yaml literal-block"&gt;
&lt;span class="nt"&gt;DOCUMENT_ROOT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/var/www&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;GATEWAY_INTERFACE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;CGI/1.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;HTTP_ACCEPT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;HTTP_ACCEPT_CHARSET&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;ISO-8859-1,utf-8;q=0.7,*;q=0.3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;HTTP_ACCEPT_ENCODING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;gzip,deflate,sdch&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;HTTP_ACCEPT_LANGUAGE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;fi-FI,fi;q=0.8,en-US;q=0.6,en;q=0.4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;HTTP_CONNECTION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;keep-alive&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;HTTP_HOST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;localhost&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;HTTP_USER_AGENT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.4 (KHTML, like Gecko)&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Ubuntu/12.10 Chromium/22.0.1229.94 Chrome/22.0.1229.94 Safari/537.4&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;PATH_INFO&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;QUERY_STRING&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;REMOTE_ADDR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;127.0.0.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;REMOTE_PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'58959'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;REQUEST_METHOD&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;GET&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;REQUEST_URI&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/python_app/environ.py&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SCRIPT_FILENAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/var/www/python_app/environ.py&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SCRIPT_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;/python_app/environ.py&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SERVER_ADDR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;127.0.0.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SERVER_ADMIN&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;webmaster&amp;#64;localhost&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SERVER_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;localhost&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SERVER_PORT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'80'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SERVER_PROTOCOL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;HTTP/1.1&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SERVER_SIGNATURE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'&amp;lt;address&amp;gt;Apache/2.2.22&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;(Ubuntu)&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Server&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;at&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;localhost&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Port&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;80&amp;lt;/address&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="s"&gt;'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;SERVER_SOFTWARE&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;Apache/2.2.22 (Ubuntu)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.application_group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;127.0.1.1|/python_app/environ.py&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.callable_object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;application&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.enable_sendfile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.handler_script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.input_chunked&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'0'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.listener_host&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.listener_port&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'80'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.process_group&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.queue_start&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'1354434559450389'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.request_handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;wsgi-script&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.script_reloading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;'1'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;mod_wsgi.version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;!!python/tuple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p-Indicator"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;3&lt;/span&gt;&lt;span class="p-Indicator"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;4&lt;/span&gt;&lt;span class="p-Indicator"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.errors&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;!!python/object:mod_wsgi.Log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p-Indicator"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.file_wrapper&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;!!python/name:None.file_wrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;''&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.input&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;!!python/object:mod_wsgi.Input&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p-Indicator"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.multiprocess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.multithread&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.run_once&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.url_scheme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l-Scalar-Plain"&gt;http&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;wsgi.version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;!!python/tuple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p-Indicator"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="p-Indicator"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="p-Indicator"&gt;]&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;A lot of info! Let's go throught some of those. The definitive reference can be
found in &lt;a class="reference external" href="http://www.python.org/dev/peps/pep-3333/#environ-variables"&gt;PEP 3333&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="document-root-var-www"&gt;
&lt;h3&gt;DOCUMENT_ROOT: /var/www&lt;/h3&gt;
&lt;p&gt;This is obviously the Apache document root.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="path-info"&gt;
&lt;h3&gt;PATH_INFO: ''&lt;/h3&gt;
&lt;p&gt;This is everything in the URL path part that comes after the script name. Here
it is empty, because there's nothing after our script name. But if you go to,
say&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/environ.py/here/is/a/path"&gt;http://localhost/python_app/environ.py/here/is/a/path&lt;/a&gt;,&amp;nbsp;PATH_INFO will
contain the string '/here/is/a/path'.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="query-string"&gt;
&lt;h3&gt;QUERY_STRING: ''&lt;/h3&gt;
&lt;p&gt;These are the URL parameters, meaning the stuff that comes after the question
mark sign in the URL. We didn't give any parameters, so it is empty. Try
this:&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/environ.py?a=1&amp;amp;b=2"&gt;http://localhost/python_app/environ.py?a=1&amp;amp;b=2&lt;/a&gt;. Now the QUERY_STRING
should be 'a=1&amp;amp;b=2'.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="request-method-get"&gt;
&lt;h3&gt;REQUEST_METHOD: GET&lt;/h3&gt;
&lt;p&gt;Well, this is the http method used to request the page. It could be GET, POST,
PUT, DELETE, HEAD, or possibly something else.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="request-uri-python-app-environ-py"&gt;
&lt;h3&gt;REQUEST_URI: /python_app/environ.py&lt;/h3&gt;
&lt;p&gt;This is the complete URL requested from the server. For example
for&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/environ.py/here/is/a/path/?a=1&amp;amp;b=2"&gt;http://localhost/python_app/environ.py/here/is/a/path/?a=1&amp;amp;b=2&lt;/a&gt;&amp;nbsp;the
REQUEST_URI will contain the string
'/python_app/environ.py?/here/is/a/path/?a=1&amp;amp;b=2'.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="script-filename-var-www-python-app-environ-py"&gt;
&lt;h3&gt;SCRIPT_FILENAME: /var/www/python_app/environ.py&lt;/h3&gt;
&lt;p&gt;This is the full file system path of the script on the server. This is &amp;quot;me&amp;quot; from
the application's point of view, in the file system.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="script-name-python-app-environ-py"&gt;
&lt;h3&gt;SCRIPT_NAME: /python_app/environ.py&lt;/h3&gt;
&lt;p&gt;This is path of the URL containing the script that was called.&amp;nbsp;This is &amp;quot;me&amp;quot; from
the application's point of view, in the requested URL.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="mod-wsgi-application-group-127-0-1-1-python-app-environ-py"&gt;
&lt;h3&gt;mod_wsgi.application_group: 127.0.1.1|/python_app/environ.py&lt;/h3&gt;
&lt;p&gt;mod_wsgi has a concept of &amp;quot;application groups&amp;quot;. This means, that you can
configure a bunch of applications to run in the same context, or Python
(sub-)interpreter. See the &lt;a class="reference external" href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIApplicationGroup"&gt;WSGIApplicationGroup&lt;/a&gt;
configuration directive for more information. For the purposes of this article,
we are using the default group given to us by mod_wsgi, which means we have a
separate group for each of our scripts.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="mod-wsgi-callable-object-application"&gt;
&lt;h3&gt;mod_wsgi.callable_object: application&lt;/h3&gt;
&lt;p&gt;This is the function (or any callable) mod_wsgi will try to call upon receiving
a request. It is configurable through the &lt;a class="reference external" href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGICallableObject"&gt;WSGICallableObject&lt;/a&gt;
configuration directive.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wsgi-errors-python-object-mod-wsgi-log"&gt;
&lt;h3&gt;wsgi.errors: !!python/object:mod_wsgi.Log {}&lt;/h3&gt;
&lt;p&gt;An output stream (file-like object) to which error output can be written. Stuff
written here should go to the error log.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wsgi-file-wrapper-python-name-none-file-wrapper"&gt;
&lt;h3&gt;wsgi.file_wrapper: !!python/name:None.file_wrapper ''&lt;/h3&gt;
&lt;p&gt;You can use this to output any
&lt;a class="reference external" href="http://docs.python.org/2/library/stdtypes.html#file-objects"&gt;file-like object&lt;/a&gt;
as the response
to the requestor. The second argument is a &amp;quot;block-size suggestion&amp;quot; according to
the documentation. I don't know what mod_wsgi does with it. Here's how to use it
to return a file as a response:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'wsgi.file_wrapper'&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;filelike&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;block_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="wsgi-input-python-object-mod-wsgi-input"&gt;
&lt;h3&gt;wsgi.input: !!python/object:mod_wsgi.Input {}&lt;/h3&gt;
&lt;p&gt;An input stream (file-like object) from which the HTTP request body bytes can be
read. You can read the raw POST or PUT request content through this.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wsgi-multiprocess-true"&gt;
&lt;h3&gt;wsgi.multiprocess: true&lt;/h3&gt;
&lt;p&gt;This tells us whether we are running in multiprocessing mode or not. As we are,
we must expect that multiple instances of the script are running in parallel as
separate processes. As they are separate processes, we can use our own local
variables without worry at this point. What we do have to worry about is using
shared objects outside the process, like files.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wsgi-multithread-false"&gt;
&lt;h3&gt;wsgi.multithread: false&lt;/h3&gt;
&lt;p&gt;This tells us whether we are running in multithreaded process or not. If this
would be true, we would have to be very careful and use
&lt;a class="reference external" href="http://docs.python.org/2/library/threading.html#lock-objects"&gt;locking&lt;/a&gt; or
&lt;a class="reference external" href="http://docs.python.org/2/library/threading.html?highlight=threading.local#threading.local"&gt;thread-local objects&lt;/a&gt;.
I encourage you to take care of it anyway, if you expect someone will actually
be using your application. It is very likely that that someone will enable
multithreading and run into very strange, random errors that are hard to debug.
But let's not worry about it at this point, we'll dive into this subject in a
later article.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wsgi-run-once-false"&gt;
&lt;h3&gt;wsgi.run_once: false&lt;/h3&gt;
&lt;p&gt;If this were true, it would mean the script is loaded and executed from scratch
for every request. As this is not true, mod_wsgi will actually only reload the
script if it detects the file has changed. So you can do all kinds of
initializations outside the &lt;em&gt;application&lt;/em&gt; callable that stay permanently for the
life time of the process. This usually means that the first request will take a
bit more time, as that is when the loading and initialization is done, but all
subsequent requests the same process handles are much quicker (just executing
the &lt;em&gt;application&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;The mod_wsgi directive
&lt;a class="reference external" href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIImportScript"&gt;WSGIImportScript&lt;/a&gt;
can be used to preload scripts before even the first request comes in.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="wsgi-url-scheme-http"&gt;
&lt;h3&gt;wsgi.url_scheme: http&lt;/h3&gt;
&lt;p&gt;This would be &amp;quot;https&amp;quot; for SSL-encrypted connections.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="modules-and-packages"&gt;
&lt;h2&gt;Modules and packages&lt;/h2&gt;
&lt;p&gt;After coding for awhile, you want to start moving stuff to separate modules and
package them up. Usually (like from the command line) you could just add module
files in the same directory where you are running your Python program. But
unfortunately this does not work with mod_wsgi so easily. Let me show you. Add a
module &lt;strong&gt;/var/www/python_app/mymodule.py&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;my_var&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;ABC&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;my_fun&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;123&amp;quot;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then, add an import statement in hello.py:&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mymodule&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;my_var&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_fun&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'200 OK'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;response_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;'Content-type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;
&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Hello world!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;This is being served using mod_wsgi&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;If you try to get the page, you'll end up with a &lt;em&gt;500 Internal Server Error&lt;/em&gt; and
an error message in the Apache log file saying something like this:&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="n"&gt;mod_wsgi&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12558&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="n"&gt;Target&lt;/span&gt; &lt;span class="n"&gt;WSGI&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="s1"&gt;'/var/www/python_app/hello.py'&lt;/span&gt; &lt;span class="n"&gt;cannot&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;loaded&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;Python&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;mod_wsgi&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;12558&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="ne"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;occurred&lt;/span&gt; &lt;span class="n"&gt;processing&lt;/span&gt; &lt;span class="n"&gt;WSGI&lt;/span&gt; &lt;span class="n"&gt;script&lt;/span&gt; &lt;span class="s1"&gt;'/var/www/python_app/hello.py'&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;/var/www/python_app/hello.py&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mymodule&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;my_var&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_fun&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="ne"&gt;ImportError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;named&lt;/span&gt; &lt;span class="n"&gt;mymodule&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;So the script directory is not in the list of paths where Python is looking for
modules and packages. We could do something like this:&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;os.path&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vm"&gt;__file__&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;site&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;addsitedir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;mymodule&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;my_var&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_fun&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'200 OK'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;response_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="s1"&gt;'Content-type'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'text/html'&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;
&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Hello world!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;This is being served using mod_wsgi&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now that works, but it is ugly, and I don't want to be adding boilerplate code
like that to every script of mine. There's a mod_wsgi directive called
&lt;a class="reference external" href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPythonPath"&gt;WSGIPythonPath&lt;/a&gt;
which can be used to achieve the same goal. But it has another problem: you
can't include it in any .htaccess file, because it needs to be set outside the
scope of any VirtualHost or Directory directive in the Apache configuration. But
you can do it if you want. Just add a line like this to your Apache default site
configuration (just add it out of the VirtualHost directive - perhaps as the
first line in the file, for example):&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nb"&gt;WSGIPythonPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/var/www/python_app&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And reload Apache. Now the import statement will work. The downside is, now all
your scripts will use that path as an import dir, which may or may not be what
you want. You could also do this:&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nb"&gt;WSGIPythonPath&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/var/www&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Reload, and make your app directory a Python package:&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nb"&gt;touch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/var/www/python_app/__init__.py&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Now you can import your module thus:&lt;/p&gt;
&lt;div class="docutils container"&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;python_app.mymodule&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;my_var&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;my_fun&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;It works, but feels a bit odd as you're actually inside the package doing the
import. And web site directories are something that I would like to be able to
rename without changing code (common modules should anyway be located somewhere
else, like&amp;nbsp;&lt;strong&gt;/usr/local/lib/python2.7/site-packages&lt;/strong&gt;).&lt;/p&gt;
&lt;p&gt;So, there are a couple of ways of doing the imports, neither of them perfect.
The choice is yours. If you happen to know a nice, clean way of doing imports in
a mod_wsgi script, please report to me! Thanks.&lt;/p&gt;
&lt;div class="section" id="hiding-things-we-don-t-want-to-serve"&gt;
&lt;h3&gt;Hiding things we don't want to serve&lt;/h3&gt;
&lt;p&gt;What's left in this section is checking out what happens when the user tries to
request our modules, compiled modules, and packages, which we don't want to
serve.&lt;/p&gt;
&lt;p&gt;First the module:&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/mymodule.py"&gt;http://localhost/python_app/mymodule.py&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That gives a &lt;em&gt;404 Not Found&lt;/em&gt;. Seems fine to me.&lt;/p&gt;
&lt;p&gt;Then the compiled module:&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/mymodule.pyc"&gt;http://localhost/python_app/mymodule.pyc&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That gives a &lt;em&gt;403 Forbidden&lt;/em&gt;. Remember, we explicitly forbade the users from
fetching our .pyc or .pyo files in the Apache configuration (right at the
beginning of this article).&lt;/p&gt;
&lt;p&gt;What about the directory:&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/"&gt;http://localhost/python_app/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That gives a &lt;em&gt;403 Forbidden&lt;/em&gt; as well. You could add an &amp;quot;index.html&amp;quot; file there
to get a default page, but we can do better.&lt;/p&gt;
&lt;p&gt;Lastly, what about the package __init__.py file:&amp;nbsp;&lt;a class="reference external" href="http://localhost/python_app/__init__.py"&gt;http://localhost/python_app/__init__.py&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;That gives a&amp;nbsp;&lt;em&gt;404 Not Found&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If this mix of 403's and 404's hurts your sense of harmony like it does mine,
you can alter the &lt;strong&gt;/etc/apache2/mods-enabled/wsgi_script.conf&lt;/strong&gt; to look like
this:&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nt"&gt;&amp;lt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mod_wsgi.c&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c"&gt;# Handle all .py files with mod_wsgi&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;FilesMatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;.+\.py$&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nb"&gt;SetHandler&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;wsgi-script&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/FilesMatch&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c"&gt;# Deny access to compiled binaries&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;RedirectMatch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;404&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;.+\.py(c|o)$&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="c"&gt;# Add a default Python index page&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;DirectoryIndex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;index.py&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/IfModule&amp;gt;&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;And Apache reload. Now there's a &lt;em&gt;404 Not Found&lt;/em&gt; for all the forbidden stuff. So
now you can put your Python applications and helper modules all in the web site
document root. If a .py file has the &lt;em&gt;application&lt;/em&gt; callable, it is a web page or
application, and will be served to the client. If it doesn't have the
&lt;em&gt;application&lt;/em&gt; callable, it is a page not found.&lt;/p&gt;
&lt;p&gt;Also, with the DirectoryIndex directive, you can add a default page for any
directory by adding an index.py page (with the &lt;em&gt;application&lt;/em&gt; callable).&lt;/p&gt;
&lt;p&gt;Now almost everything seems perfect. Let's move on to the last subject for
tonight.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="webob-wsgi-request-and-response-objects"&gt;
&lt;h2&gt;WebOb - WSGI request and response objects&lt;/h2&gt;
&lt;p&gt;Parsing the raw WSGI environment variables for each request and adding the
response headers and status codes with robust exception handling is a tedious,
error-prone and most of all boring job after awhile. Because I don't want you to
start hacking away implementing that next, I will just quickly introduce you to
an excellent&amp;nbsp;library for doing all the boring stuff, and a bit more. That
library is called &lt;a class="reference external" href="http://webob.org/"&gt;WebOb&lt;/a&gt;. So let's just:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;apt-get&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;python-webob
&lt;/pre&gt;
&lt;p&gt;And then make a WebOb enabled app (let's make it &lt;strong&gt;hello_webob.py&lt;/strong&gt;):&lt;/p&gt;
&lt;pre class="code python literal-block"&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;webob&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;  &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;  &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;  &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;
&amp;lt;html&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;h1&amp;gt;Hello world!&amp;lt;/h1&amp;gt;
&amp;lt;p&amp;gt;This is being served using mod_wsgi and WebOb&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;
 &amp;lt;form action=&amp;quot;&amp;quot; method=&amp;quot;POST&amp;quot;&amp;gt;
 a: &amp;lt;input name=&amp;quot;a&amp;quot; value=&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; /&amp;gt; &amp;lt;br /&amp;gt;
 b: &amp;lt;input name=&amp;quot;b&amp;quot; value=&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot; /&amp;gt; &amp;lt;br /&amp;gt;
 &amp;lt;input type=&amp;quot;submit&amp;quot; value=&amp;quot;Send&amp;quot; /&amp;gt;
 &amp;lt;/form
&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Your a parameters are: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;
&amp;lt;p&amp;gt;Your b parameters are: &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;       &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;       &lt;span class="s2"&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'a'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;       &lt;span class="s2"&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'b'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;  &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                      &lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;text/html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                      &lt;span class="n"&gt;charset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;utf8&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;                      &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;200 OK&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start_response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;It's a bit longer than the previous hello.py, but it does a lot more. Try giving
it parameters using the inputs, using URL vars, or even both. And it takes extra
path arguments, everything at the same time.&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://localhost/python_app/hello_webob.py"&gt;http://localhost/python_app/hello_webob.py&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://localhost/python_app/hello_webob.py?a=1&amp;amp;a=2&amp;amp;b=3"&gt;http://localhost/python_app/hello_webob.py?a=1&amp;amp;a=2&amp;amp;b=3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://localhost/python_app/hello_webob.py/sub/path/here"&gt;http://localhost/python_app/hello_webob.py/sub/path/here&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://localhost/python_app/hello_webob.py/sub/path/here?b=a&amp;amp;a=b"&gt;http://localhost/python_app/hello_webob.py/sub/path/here?b=a&amp;amp;a=b&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This sunday night is getting late so that's all for now. I will write a
follow-up on this. I need to discuss WebOb some more, multiprocessing and
multithreading issues, exception handling, and there's lots of other stuff to
talk about.&lt;/p&gt;
&lt;p&gt;Have fun with trying it out! And report any security issues my setup might have,
or any other insights.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Edit: Check out&lt;/em&gt;&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/serving-python-scripts-with-apache-mod_wsgi-part-ii-mod_rewrite/"&gt;part II - mod_rewrite&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="useful-links"&gt;
&lt;h2&gt;Useful links:&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;mod_wsgi:&amp;nbsp;&lt;a class="reference external" href="http://code.google.com/p/modwsgi/"&gt;http://code.google.com/p/modwsgi/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;PEP 3333: Python Web Server Gateway Interface v1.0.1:&amp;nbsp;&lt;a class="reference external" href="http://www.python.org/dev/peps/pep-3333/"&gt;http://www.python.org/dev/peps/pep-3333/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;WebOb:&amp;nbsp;&lt;a class="reference external" href="http://webob.org/"&gt;http://webob.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Apache"></category><category term="mod_wsgi"></category><category term="Python"></category><category term="Web"></category></entry><entry><title>AWStats Multi-Site Setup</title><link href="https://mikko.kortelainen.io/blog/awstats-multi-site-setup/" rel="alternate"></link><published>2012-12-01T16:57:00+02:00</published><updated>2012-12-01T16:57:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-12-01:/blog/awstats-multi-site-setup/</id><summary type="html">&lt;p&gt;Here's how to install and configure &lt;a class="reference external" href="http://awstats.sourceforge.net/"&gt;AWStats&lt;/a&gt; to compile separate statistics about multiple Apache sites or virtual hosts running on a single server. This can be done when you configure each Apache site or virtual host to use a different access log file.&lt;/p&gt;
&lt;p&gt;The following instructions have been tested on …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's how to install and configure &lt;a class="reference external" href="http://awstats.sourceforge.net/"&gt;AWStats&lt;/a&gt; to compile separate statistics about multiple Apache sites or virtual hosts running on a single server. This can be done when you configure each Apache site or virtual host to use a different access log file.&lt;/p&gt;
&lt;p&gt;The following instructions have been tested on Ubuntu 12.04.&lt;/p&gt;
&lt;div class="section" id="install"&gt;
&lt;h2&gt;Install&lt;/h2&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install awstats
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-awstats-for-the-default-site"&gt;
&lt;h2&gt;Configure AWStats for the default site&lt;/h2&gt;
&lt;p&gt;Edit the &lt;strong&gt;/etc/awstats/awstats.conf.local&lt;/strong&gt; file and not the master configuration file. The main awstats.conf file is a good reference for all the configuration options, of which there are plenty.&lt;/p&gt;
&lt;p&gt;The only thing you really need to start gathering stats for your default-site, is enter your web server's default site domain name &lt;strong&gt;/etc/awstats/awstats.conf.local&lt;/strong&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
SiteDomain=&amp;quot;my.domain&amp;quot;
&lt;/pre&gt;
&lt;p&gt;That is all that is needed for AWStats to make statistics out of the default site. We will add more configuration files later, one for each site or virtual host we want to get statistics for. But we must fix a couple of things first.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="fix-log-file-permissions"&gt;
&lt;h2&gt;Fix log file permissions&lt;/h2&gt;
&lt;p&gt;AWStats update script will run every 10 minutes as the user &amp;quot;www-data&amp;quot; (see &lt;strong&gt;/etc/cron.d/awstats&lt;/strong&gt;). The Apache log files are by default not readable by the user www-data, so something must be done about that.&lt;/p&gt;
&lt;p&gt;Edit &lt;strong&gt;/etc/logrotate.d/apache2&lt;/strong&gt; and give Apache log file read permissions to everybody. This may not be a good idea on a server with untrusted users with shell access, but mine has none.&lt;/p&gt;
&lt;p&gt;Change the following line:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
create 640 root adm
&lt;/pre&gt;
&lt;p&gt;To:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
create 644 root adm
&lt;/pre&gt;
&lt;p&gt;Save, and then change the permissions of the existing log files:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo chmod o+r /var/log/apache2/*.log
&lt;/pre&gt;
&lt;p&gt;Also, give permission to access the directory:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo chmod o+x /var/log/apache2
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="ensure-logrotate-does-not-skew-your-statistics"&gt;
&lt;h2&gt;Ensure logrotate does not skew your statistics&lt;/h2&gt;
&lt;p&gt;AWStats runs every ten minutes, but logrotate might rotate a log file whenever it gets full, which will cause AWStats to miss some hits.&lt;/p&gt;
&lt;p&gt;To ensure AWStats update script is always run before a logfile is rotated, we need to add a script for that. Add the following directory:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo mkdir -p /etc/logrotate.d/httpd-prerotate
&lt;/pre&gt;
&lt;p&gt;Add the update script:&lt;/p&gt;
&lt;pre class="code sh literal-block"&gt;
sudo&lt;span class="w"&gt; &lt;/span&gt;tee&lt;span class="w"&gt; &lt;/span&gt;/etc/logrotate.d/httpd-prerotate/awstats&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;&amp;lt; 'EOF'
#!/bin/sh
if [ -x /usr/share/awstats/tools/update.sh ]; then
  su -l -c /usr/share/awstats/tools/update.sh www-data
fi
EOF&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;Give execute permission:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo chmod ug+x /etc/logrotate.d/httpd-prerotate/awstats
&lt;/pre&gt;
&lt;p&gt;At this point, you can run the statistics collector from the command line:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo su -l -c /usr/share/awstats/tools/update.sh www-data
&lt;/pre&gt;
&lt;p&gt;If there are no error messages, you should now have up-to-date statistics collected. Let's get a site up and running to display the stats.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-apache"&gt;
&lt;h2&gt;Configure Apache&lt;/h2&gt;
&lt;p&gt;Now that we have some real data, let's set up a location where we can actually take a look at it. There's an example Apache configuration file in &lt;strong&gt;/usr/share/doc/awstats/examples/apache.conf&lt;/strong&gt;. But don't copy it directly to Apache configuration directory. I added something like this to my default site file under /etc/apache2/sites-enabled:&lt;/p&gt;
&lt;pre class="code apache literal-block"&gt;
&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/var/lib/awstats&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;AllowOverride&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;allow,deny&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Allow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/share/awstats/icon&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;AllowOverride&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;allow,deny&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Allow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/share/java/awstats&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Options&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;FollowSymLinks&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;AllowOverride&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;None&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;allow,deny&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Allow&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;from&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;all&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/usr/lib/cgi-bin&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;AuthType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;Basic&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;AuthName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Unauthorized use prohibited&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;AuthBasicProvider&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;file&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;AuthUserFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/etc/apache2/htpasswd/htpasswd.awstats&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nb"&gt;Require&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;valid-user&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="nb"&gt;ScriptAlias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/awstats.pl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/usr/lib/cgi-bin/awstats.pl&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/awstats-icon/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/usr/share/awstats/icon/&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nb"&gt;Alias&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/awstatsclasses/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sx"&gt;/usr/share/java/awstats/&lt;/span&gt;
&lt;/pre&gt;
&lt;p&gt;That will require a username and password to access the stats. It is a good idea to use an SSL-secured version of the default site, and use that instead of unsecured one. You can run &amp;quot;&lt;strong&gt;a2ensite default-ssl&amp;quot;&lt;/strong&gt; to enable the default SSL site.&lt;/p&gt;
&lt;p&gt;The above configuration will actually from now on require a password for all your cgi scripts dwelling under &lt;strong&gt;/usr/lib/cgi-bin&lt;/strong&gt;, so if you have something there you wish not to protect, move the awstats.pl to somewhere else and secure that instead.&lt;/p&gt;
&lt;p&gt;To add the username and password for access:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo mkdir -p /etc/apache2/htpasswd
sudo htpasswd -c /etc/apache2/htpasswd/htpasswd.awstats myusername
&lt;/pre&gt;
&lt;p&gt;Reload Apache configuration:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
/etc/init.d/apache2 reload
&lt;/pre&gt;
&lt;p&gt;And then point your browser to &lt;strong&gt;http(s)://my.domain/awstats.pl&lt;/strong&gt; to see some statistics!&lt;/p&gt;
&lt;p&gt;Next, let's move on to configuring separate statistics for multiple sites.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-awstats-for-multiple-sites"&gt;
&lt;h2&gt;Configure AWStats for multiple sites&lt;/h2&gt;
&lt;p&gt;Place all additional configs in &lt;strong&gt;/etc/awstats/&lt;/strong&gt;. Name the new configs &lt;strong&gt;&amp;quot;awstats.&amp;quot; + domain.name + &amp;quot;.conf&amp;quot;&lt;/strong&gt;, eg. &lt;strong&gt;awstats.my.other.domain.conf&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In each file, include the main awstats.conf file. The first line should be:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Include &amp;quot;/etc/awstats/awstats.conf&amp;quot;
&lt;/pre&gt;
&lt;p&gt;After that, we need to configure at least the SiteDomain directive, the location of the Apache log file to scan, and place to put the statistics data. For example:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
Include &amp;quot;/etc/awstats/awstats.conf&amp;quot;
SiteDomain=&amp;quot;my.other.domain&amp;quot;
HostAliases=&amp;quot;my.other.domain www.my.other.domain&amp;quot;
DirData=&amp;quot;/var/lib/awstats/my.other.domain&amp;quot;
LogFile=&amp;quot;/var/log/apache2/my.other.domain_access_log&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Make sure you get the LogFile path right (take a look at your Apache configuration to find out where it should be).&lt;/p&gt;
&lt;p&gt;Also, create the directory for the statistics:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo mkdir -p /var/lib/awstats/my.other.domain
sudo chown www-data:www-data /var/lib/awstats/my.other.domain
&lt;/pre&gt;
&lt;p&gt;The next time AWStats runs, within the next 10 minutes, it will collect statistics about this other site. If you are impatient, or want to see if you made any mistakes with your configuration, you can run it manually:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo su -l -c /usr/share/awstats/tools/update.sh www-data
&lt;/pre&gt;
&lt;p&gt;Now we have data for this site.&lt;/p&gt;
&lt;p&gt;Repeat the procedure for all other sites you have:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Add a configuration file&lt;/li&gt;
&lt;li&gt;Create a stats directory with the right permissions&lt;/li&gt;
&lt;li&gt;Gather stats&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="section" id="accessing-statistics-for-other-sites-than-the-default-site"&gt;
&lt;h2&gt;Accessing statistics for other sites than the default-site&lt;/h2&gt;
&lt;p&gt;To see the statistics, browse to your default site's awstats.pl script, but give it a &amp;quot;config&amp;quot; url parameter:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;http(s)://my.domain/awstats.pl?config=my.other.domain&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;You can also configure AWStats separately for each site's Apache configuration file, so you can use URLs like this: http(s)://my.other.domain/awstats.pl.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Apache"></category><category term="Web"></category></entry><entry><title>Hunajapurkki: A honeypot link widget for WordPress</title><link href="https://mikko.kortelainen.io/blog/hunajapurkki-a-honeypot-link-widget-for-wordpress/" rel="alternate"></link><published>2012-12-01T01:06:00+02:00</published><updated>2012-12-01T01:06:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-12-01:/blog/hunajapurkki-a-honeypot-link-widget-for-wordpress/</id><summary type="html">&lt;p&gt;As a first excercise in creating WordPress plugins, I decided to write an extremely simple widget which can be used to lure spammers' address harvester bots to &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Honeypot_(computing)"&gt;honeypots&lt;/a&gt;, for example ones set up using the&amp;nbsp;&lt;a class="reference external" href="http://projecthoneypot.org/"&gt;Project Honey Pot&lt;/a&gt;&amp;nbsp;web site. If you want to help fight spam, just sign up …&lt;/p&gt;</summary><content type="html">&lt;p&gt;As a first excercise in creating WordPress plugins, I decided to write an extremely simple widget which can be used to lure spammers' address harvester bots to &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Honeypot_(computing)"&gt;honeypots&lt;/a&gt;, for example ones set up using the&amp;nbsp;&lt;a class="reference external" href="http://projecthoneypot.org/"&gt;Project Honey Pot&lt;/a&gt;&amp;nbsp;web site. If you want to help fight spam, just sign up for free at their page and follow the instructions. You can add your honeypot to your WordPress site using the Hunajapurkki widget.You can use either the QuickLink URL, which is extremely simple, or set up your own honeypot on your own server if you're feeling a bit more adventurous. In both cases, you should end up with a URL which is the honeypot. You will add this URL to the Hunajapurkki widget.&lt;/p&gt;
&lt;div class="section" id="installation-of-hunajapurkki"&gt;
&lt;h2&gt;Installation of Hunajapurkki&lt;/h2&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Download&amp;nbsp;&lt;a class="reference external" href="https://mikko.kortelainen.io/blog/files/Hunajapurkki.zip"&gt;Hunajapurkki.zip&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Unzip &lt;strong&gt;Hunajapurkki.zip&lt;/strong&gt;&amp;nbsp;to the &lt;strong&gt;/wp-content/plugins/&lt;/strong&gt; directory.&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Appearance&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Widgets&lt;/strong&gt; and add a Hunajapurkki wherever you wish and as many times as you wish.&lt;/li&gt;
&lt;li&gt;For each added widget, you must provide a honeypot URL&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Remember, the widget should in no way be visible on the page to anyone browsing the&amp;nbsp;site. There should be nothing, not even empty space, shown where you added the widget.&lt;/p&gt;
&lt;p&gt;If you want to confirm the installation was successful, you can look at your page&amp;nbsp;source code and search for &amp;quot;hunajapurkki&amp;quot;. Your honeypot link should show up there. In fact, if you look at the source code of my blog's front page, or any page in it, you should be able to find one or two honeypots there.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="technical-details"&gt;
&lt;h2&gt;Technical details&lt;/h2&gt;
&lt;p&gt;What will be added in place of the widget is html like this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;div style='display: none;'&amp;gt;
 &amp;lt;a href='http://link-to-the-honeypot'&amp;gt;
   &amp;lt;span style='display: none;'&amp;gt;
     &amp;lt;!-- http://link-to-the-honeypot --&amp;gt;
   &amp;lt;/span&amp;gt;
 &amp;lt;/a&amp;gt;
&amp;lt;/div&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Any modern browser should display nothing on the screen, because of the &amp;quot;display:none&amp;quot; CSS attribute. The a tag intentionally does not have the &amp;quot;display:none&amp;quot; attribute in case the spambot is looking for it. Also, the link has content in it for the same reason.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;I have tested&amp;nbsp;with Firefox, Chrome and Opera, and Internet Explorer down to IE7 using&lt;/div&gt;
&lt;div class="line"&gt;the sidebar of the default WP 3.4 theme, and it seems to behave fine.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;In case you are wondering about the strange name of the widget,&amp;nbsp;&lt;em&gt;Hunajapurkki&lt;/em&gt;, it comes&amp;nbsp;from the&amp;nbsp;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/Finnish_language"&gt;Finnish language&lt;/a&gt;,&amp;nbsp;meaning literally 'a honey pot'.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="PHP"></category><category term="Wordpress"></category></entry><entry><title>ADT requires org.eclipse.wst.sse.core 0.0.0 but it could not be found</title><link href="https://mikko.kortelainen.io/blog/adt-requires-org-eclipse-wst-sse-core-0-0-0-but-it-could-not-be-found/" rel="alternate"></link><published>2012-11-29T16:35:00+02:00</published><updated>2012-11-29T16:35:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-11-29:/blog/adt-requires-org-eclipse-wst-sse-core-0-0-0-but-it-could-not-be-found/</id><summary type="html">&lt;p&gt;In Eclipse 3.8, installing the Android Development tools may fail with the following error:&lt;/p&gt;
&lt;blockquote&gt;
Cannot complete the install because one or more required items could not be found. Software being installed: Android Development Tools 0.9.9.v201009221407-60953 (com.android.ide.eclipse.adt.feature.group 0.9.9.v201009221407-60953 …&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;In Eclipse 3.8, installing the Android Development tools may fail with the following error:&lt;/p&gt;
&lt;blockquote&gt;
Cannot complete the install because one or more required items could not be found. Software being installed: Android Development Tools 0.9.9.v201009221407-60953 (com.android.ide.eclipse.adt.feature.group 0.9.9.v201009221407-60953) Missing requirement: Android Development Tools 0.9.9.v201009221407-60953 (com.android.ide.eclipse.adt.feature.group 0.9.9.v201009221407-60953) requires 'org.eclipse.wst.sse.core 0.0.0' but it could not be found&lt;/blockquote&gt;
&lt;p&gt;The fix is to add the &amp;quot;Helios&amp;quot; update site in addition to the ADT one. The correct URL is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;a class="reference external" href="http://download.eclipse.org/releases/helios"&gt;http://download.eclipse.org/releases/helios&lt;/a&gt;&lt;/blockquote&gt;
&lt;p&gt;Thanks go to:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://stackoverflow.com/questions/4249695/adt-requires-org-eclipse-wst-sse-core-0-0-0-but-it-could-not-be-found"&gt;android - ADT requires org.eclipse.wst.sse.core 0.0.0 but it could not be found - Stack Overflow&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://code.google.com/intl/es/eclipse/docs/faq.html#wstinstallerror"&gt;http://code.google.com/intl/es/eclipse/docs/faq.html#wstinstallerror&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Blog"></category><category term="Android"></category><category term="Eclipse"></category><category term="Java"></category></entry><entry><title>ACPI Shutdown on Virtual Ubuntu</title><link href="https://mikko.kortelainen.io/blog/acpi-shutdown-on-virtual-ubuntu/" rel="alternate"></link><published>2012-11-29T15:10:00+02:00</published><updated>2012-11-29T15:10:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-11-29:/blog/acpi-shutdown-on-virtual-ubuntu/</id><summary type="html">&lt;p&gt;If your virtual machine does not shut down when asked by the hypervisor, install the package acpi-support.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install acpi-support
&lt;/pre&gt;
&lt;p&gt;Works at least with KVM, but I see no reason why it would not work as well in other virtualization platforms, if they just send the ACPI shutdown signal …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If your virtual machine does not shut down when asked by the hypervisor, install the package acpi-support.&lt;/p&gt;
&lt;pre class="literal-block"&gt;
sudo apt-get install acpi-support
&lt;/pre&gt;
&lt;p&gt;Works at least with KVM, but I see no reason why it would not work as well in other virtualization platforms, if they just send the ACPI shutdown signal to VM.&lt;/p&gt;
&lt;p&gt;Thanks:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://redscreen.wordpress.com/2011/02/13/virtualbox-acpi-shutdown-on-ubuntu-lucid-lynx/"&gt;Virtualbox ACPI Shutdown on Ubuntu Lucid Lynx « The Redscreen Blog&lt;/a&gt;&lt;a class="reference external" href="http://redscreen.wordpress.com/2011/02/13/virtualbox-acpi-shutdown-on-ubuntu-lucid-lynx/"&gt;.&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Blog"></category><category term="KVM"></category><category term="Linux"></category><category term="Ubuntu"></category><category term="Virtualization"></category></entry><entry><title>Wordpress Logins and Administration over SSL</title><link href="https://mikko.kortelainen.io/blog/wordpress-logins-over-ssl/" rel="alternate"></link><published>2012-11-27T09:52:00+02:00</published><updated>2012-11-27T09:52:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-11-27:/blog/wordpress-logins-over-ssl/</id><summary type="html">&lt;p&gt;To force SSL logins and the administration interface, edit wp-config.php and add
these before the &lt;em&gt;&amp;quot;/* That's all, stop editing! Happy blogging. */&amp;quot;&lt;/em&gt;&amp;nbsp;line:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
define('FORCE_SSL_LOGIN', true);
define('FORCE_SSL_ADMIN', true);

/* That's all, stop editing! Happy blogging. */
&lt;/pre&gt;
&lt;p&gt;You must set up Apache to use SSL of course.&lt;/p&gt;
&lt;p&gt;A lot more info can …&lt;/p&gt;</summary><content type="html">&lt;p&gt;To force SSL logins and the administration interface, edit wp-config.php and add
these before the &lt;em&gt;&amp;quot;/* That's all, stop editing! Happy blogging. */&amp;quot;&lt;/em&gt;&amp;nbsp;line:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
define('FORCE_SSL_LOGIN', true);
define('FORCE_SSL_ADMIN', true);

/* That's all, stop editing! Happy blogging. */
&lt;/pre&gt;
&lt;p&gt;You must set up Apache to use SSL of course.&lt;/p&gt;
&lt;p&gt;A lot more info can be found here:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://codex.wordpress.org/Administration_Over_SSL"&gt;Administration Over SSL « WordPress Codex&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Blog"></category><category term="Wordpress"></category></entry><entry><title>Get Internet Explorer 7 to work under Crossover Office in Ubuntu 12.10</title><link href="https://mikko.kortelainen.io/blog/get-internet-explorer-7-to-work-under-crossover-office-in-ubuntu-12-10/" rel="alternate"></link><published>2012-11-26T13:17:00+02:00</published><updated>2012-11-26T13:17:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-11-26:/blog/get-internet-explorer-7-to-work-under-crossover-office-in-ubuntu-12-10/</id><summary type="html">&lt;p&gt;If IE7 just keeps opening the &lt;em&gt;runonce3.aspx&lt;/em&gt;, you can use this to make it forget about it:&lt;/p&gt;
&lt;p&gt;Disable ptrace security (please don't do this on a multi-user machine - see the codeweavers support wiki instructions regarding security):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
&lt;/pre&gt;
&lt;p&gt;To make it permanent …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If IE7 just keeps opening the &lt;em&gt;runonce3.aspx&lt;/em&gt;, you can use this to make it forget about it:&lt;/p&gt;
&lt;p&gt;Disable ptrace security (please don't do this on a multi-user machine - see the codeweavers support wiki instructions regarding security):&lt;/p&gt;
&lt;pre class="literal-block"&gt;
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
&lt;/pre&gt;
&lt;p&gt;To make it permanent, edit&amp;nbsp;&lt;em&gt;/etc/sysctl.d/10-ptrace.conf&lt;/em&gt; and set:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
kernel.yama.ptrace_scope = 0
&lt;/pre&gt;
&lt;p&gt;That will make other Windows programs run in Ubuntu as well. While the above is all that is needed to run IE7, you can disable the Run Once dialog as follows:&lt;/p&gt;
&lt;p&gt;Make changes to the registry by opening the &lt;em&gt;&amp;quot;Run a Windows Command&amp;quot;&lt;/em&gt; from the launcher, and running &lt;em&gt;&amp;quot;regedit&amp;quot;&lt;/em&gt; in the bottle where you have IE7 installed.&lt;/p&gt;
&lt;p&gt;This makes IE7 think the runonce page has been completed:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main]
&amp;quot;RunOnceHasShown&amp;quot;=dword:00000001
&amp;quot;RunOnceComplete&amp;quot;=dword:00000001
&lt;/pre&gt;
&lt;p&gt;While you're at it, this will change the default search page to Google:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
[HKEY_CURRENT_USER\Software\Microsoft\Internet
Explorer\SearchScopes\{2FEDD0BC-4D55-413C-8B59-BFE70133A2CB}]
&amp;quot;DisplayName&amp;quot;=&amp;quot;Google&amp;quot;
&amp;quot;URL&amp;quot;=&amp;quot;http://www.google.com/search?q={searchTerms}&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Thanks go to:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://ramblings.narrabilis.com/ie7-runonce"&gt;internet explorer 7 ie7 in crossover office shows runonce.msn.com/runonce3.aspx every time | ramblings.narrabilis.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.codeweavers.com/support/wiki/linux/faq/ubuntu1204"&gt;http://www.codeweavers.com/support/wiki/linux/faq/ubuntu1204&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://support.microsoft.com/kb/945385"&gt;http://support.microsoft.com/kb/945385&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Blog"></category><category term="Crossover Office"></category><category term="Internet Explorer"></category></entry><entry><title>Hello again, world!</title><link href="https://mikko.kortelainen.io/blog/hello-world/" rel="alternate"></link><published>2012-11-23T07:36:00+02:00</published><updated>2012-11-23T07:36:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2012-11-23:/blog/hello-world/</id><summary type="html">&lt;p&gt;I'm just trying to get my old blog back online after neglecting it for a couple of years. And a disk crash. And no MySQL dumps, of course. Luckily I had the MyISAM data files so I was able to salvage most of it. Lot's of stuff not working yet …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I'm just trying to get my old blog back online after neglecting it for a couple of years. And a disk crash. And no MySQL dumps, of course. Luckily I had the MyISAM data files so I was able to salvage most of it. Lot's of stuff not working yet. Working on it.&lt;/p&gt;
</content><category term="Blog"></category><category term="Site info"></category></entry><entry><title>Cloning Ubuntu 10.04 Server KVM guests efficiently</title><link href="https://mikko.kortelainen.io/blog/cloning-ubuntu-1004-server-kvm-guests-efficiently/" rel="alternate"></link><published>2010-11-28T12:05:00+02:00</published><updated>2010-11-28T12:05:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2010-11-28:/blog/cloning-ubuntu-1004-server-kvm-guests-efficiently/</id><summary type="html">&lt;p&gt;If you need to create lots of similar virtual machine guests running on QEMU/KVM, it is a very good idea to prepare a template guest image from which to clone the other guests. You should do whatever customizations you like before cloning. For instance I like to configure LVM …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you need to create lots of similar virtual machine guests running on QEMU/KVM, it is a very good idea to prepare a template guest image from which to clone the other guests. You should do whatever customizations you like before cloning. For instance I like to configure LVM and file systems to my liking, install openssh-server, install nfs-common and configure NFS mounts, install all available updates, add users or set up authentication, copy ssh keys, and do many other things so that they will be working out-of-the-box after cloning a number of guests from the template.&lt;/p&gt;
&lt;p&gt;After you have installed and set-up your template virtual server to your liking, and would want to start cloning multiple instances of it, some tricks are needed to make things work more automatically after cloning and starting up the final copy.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;If you simply clone a vanilla Ubuntu server installation multiple times, you will face some problems:&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;The network interfaces will be renamed at first boot because the MAC address will be different.&lt;/li&gt;
&lt;li&gt;The ssh keys will be the same on each server (it works, but not the best idea)&lt;/li&gt;
&lt;li&gt;The server hostname will be the same on each server&lt;/li&gt;
&lt;li&gt;Statically configured IP address will be the same on each server, causing potential IP address conflicts&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For IP addresses, I suggest using DHCP for the template image, so that each cloned guest will receive a unique IP during the first boot-up. You can then configure static IP addresses for the clones. I will show you how to do it almost automatically.&lt;/p&gt;
&lt;p&gt;There are also a couple of optional tips which you should do for a virtual guest template before anything else.&lt;/p&gt;
&lt;p&gt;This long post is divided into three parts:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Part I. Configuring the template guest image&lt;/li&gt;
&lt;li&gt;Part II. Cloning and configuring multiple guests from your template&lt;/li&gt;
&lt;li&gt;Part III. Conclusions and recommendations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Part I is the longest, but it will show you how to set up your template so that only one script must be run after guest boot-up to change network settings and hostname for each new guest. Also, I will show you how to make sure network interface naming is consistent from eth0 onwards, and that the host ssh keys will be unique on each host.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="part-i-configuring-the-template-guest-image"&gt;
&lt;h2&gt;Part I. Configuring the template guest image&lt;/h2&gt;
&lt;p&gt;Let's start with the tips:&lt;/p&gt;
&lt;div class="section" id="tip-1-make-shutdown-work"&gt;
&lt;h3&gt;Tip 1: Make shutdown work&lt;/h3&gt;
&lt;p&gt;The shutdown command does not work by default from virt-manager nor virsh. To fix that, install acpid on the template guest image:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo apt-get install acpid
&lt;/pre&gt;
&lt;p&gt;After that, shutdown should work from both virt-manager and virsh. For some strange reason, reboot works only from virt-manager, not virsh.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tip-2-make-serial-console-work"&gt;
&lt;h3&gt;Tip 2: Make serial console work&lt;/h3&gt;
&lt;p&gt;This is very handy for console over ssh (no need for virt-manager, nor any kind of VNC connection for console). See earlier post:&lt;/p&gt;
&lt;p&gt;{filename}/2010/serial-console-for-ubuntu-server-1004-kvm-guests.rst&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="tip-3-copy-your-ssh-public-key"&gt;
&lt;h3&gt;Tip 3: Copy your ssh public key&lt;/h3&gt;
&lt;p&gt;It makes sense to copy your public ssh key at this point, so that you don't need to do it again for each guest. Simply go to your home directory on the template guest and run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkdir -p .ssh
chmod 700 .ssh
cd .ssh
cat &amp;gt;authorized_keys
&lt;/pre&gt;
&lt;p&gt;Paste your public key there, and press &lt;strong&gt;Ctrl-D&lt;/strong&gt;. Pasting does not work in a VNC console, but does work using the serial console trick mentioned in tip 2, or ssh connection.&lt;/p&gt;
&lt;p&gt;Next, let's take a look at the problems mentioned in the start of the post:&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="problem-1-network-interface-naming"&gt;
&lt;h3&gt;Problem 1: Network interface naming&lt;/h3&gt;
&lt;p&gt;When Ubuntu boots up and detects a network interface with a MAC address which it has not seen before, it will take the next available eth number and add that to the udev rules file. The MAC addresses of network interfaces for cloned guests will be different from the template guest, so if you don't delete the corresponding lines from the file before cloning, the cloned guest's interface numbering will not start from eth0, but eth1 or something else depending on the number of interfaces you have configured.&lt;/p&gt;
&lt;p&gt;In order to get your cloned guests' network interfaces start being numbered from eth0 onwards, simply delete the udev file which contains the rules for interface naming:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
rm -f /etc/udev/rules.d/70-persistent-net.rules
&lt;/pre&gt;
&lt;p&gt;That file will be regenerated at the first boot, so all clones will start their interface naming from eth0. But you must also remember that the next time you start up your template to make changes to it, it too will re-create the file. So remember to delete it every time you start up your template guest to make changes to it.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="problem-2-individual-ssh-host-keys"&gt;
&lt;h3&gt;Problem 2: Individual SSH host keys&lt;/h3&gt;
&lt;p&gt;The ssh host keys are a bit more difficult thing. If you simply delete the keys from /etc/ssh/, they will not be regenerated automatically on Ubuntu. To make that happen, you need to run manually:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo dpkg-reconfigure openssh-server
&lt;/pre&gt;
&lt;p&gt;In order to make that happen automatically during the first boot of a cloned guest, one line has to be added to the /etc/init/ssh.conf file (marked with bold):&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/etc/init/ssh.conf:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
respawn
respawn limit 10 5
umask 022
# replaces SSHD_OOM_ADJUST in /etc/default/ssh
oom never

pre-start script
    test -x /usr/sbin/sshd || { stop; exit 0; }
    test -e /etc/ssh/sshd_not_to_be_run &amp;amp;&amp;amp; { stop; exit 0; }
    test -c /dev/null || { stop; exit 0; }

    # Regenerate ssh host keys if they are missing:
    test -f /etc/ssh/ssh_host_dsa_key || dpkg-reconfigure openssh-server

    mkdir -p -m0755 /var/run/sshd
end script

# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
# 'exec' line here instead
exec /usr/sbin/sshd
&lt;/pre&gt;
&lt;p&gt;That will test the existence of host keys, and regenerate them if they are not present.&lt;/p&gt;
&lt;p&gt;Before stopping your template guest, delete the ssh host keys:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
rm -f /etc/ssh/*host*key*
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="script-to-prepare-template-for-cloning"&gt;
&lt;h3&gt;Script to prepare template for cloning&lt;/h3&gt;
&lt;p&gt;I added a simple script, /usr/local/sbin/cloneprep, to ease the preparation of the template. It will simply delete your host ssh keys and udev persistent network rules (asking your permission first), and shut down the template guest afterwards so you can start cloning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/usr/local/sbin/cloneprep:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/bin/sh

echo &amp;quot;TEMPLATE PREPARATION BEFORE CLONING&amp;quot;
echo
echo &amp;quot;This script will prepare this host for cloning. The network interface&amp;quot;
echo &amp;quot;name rules and ssh host keys will be deleted, but they will be&amp;quot;
echo &amp;quot;regenerated at the next boot (run sudo dpkg-reconfigure openssh-server&amp;quot;
echo &amp;quot;to regenerate ssh keys if needed).&amp;quot;
echo
echo &amp;quot;Are you sure you want to remove the ssh keys and network interface&amp;quot;
echo -n &amp;quot;rules on this host [y/N]? &amp;quot;

read YN

if [ &amp;quot;$YN&amp;quot; != &amp;quot;y&amp;quot; ]; then
  echo abort.
  exit 1
fi

echo
echo Removing persistent network interface rules...
rm -f /etc/udev/rules.d/70-persistent-net.rules

echo Removing host ssh keys...
rm -f /etc/ssh/*host*key*

echo
echo Your image is now ready for cloning. The machine will shut down.
echo

for i in 12 11 10 9 8 7 6 5 4 3 2 1; do echo &amp;quot;Halting machine in $i seconds (Ctrl-C to abort)&amp;quot;; sleep 1; done

halt
&lt;/pre&gt;
&lt;p&gt;Give execute permission with &amp;quot;sudo chmod u+x /usr/local/sbin/cloneprep&amp;quot;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Remember to run cloneprep EVERY TIME you start up a template guest machine to change something. Don't use halt or shutdown, but run cloneprep instead.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is not yet time to run it though, as we will do some further preparations to the template in the following section.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="problems-3-and-4-hostname-and-ip-address"&gt;
&lt;h3&gt;Problems 3 and 4: Hostname and IP address&lt;/h3&gt;
&lt;p&gt;To address these problems efficiently, we must create three of configuration files and a configuration script that will be run on each guest after the first boot.&lt;/p&gt;
&lt;p&gt;To create a dozen guests, I created the following files under the template guest's /usr/local/etc.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;strong&gt;/usr/local/etc/cloneaddresses:&lt;/strong&gt;&lt;/div&gt;
&lt;div class="line"&gt;This file will be used to look up the IP address for a given name.&lt;/div&gt;
&lt;/div&gt;
&lt;pre class="code literal-block"&gt;
guest01 192.168.1.101
guest02 192.168.1.102
guest03 192.168.1.103
guest04 192.168.1.104
guest05 192.168.1.105
guest06 192.168.1.106
guest07 192.168.1.107
guest08 192.168.1.108
guest09 192.168.1.109
guest10 192.168.1.110
guest11 192.168.1.111
guest12 192.168.1.112
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;(Use spaces instead of tabs in the cloneaddresses file. You can add as many spaces in between the names and addresses as you like, though.)&lt;/em&gt;&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;strong&gt;/usr/local/etc/clonehosts:&lt;/strong&gt;&lt;/div&gt;
&lt;div class="line"&gt;This file will be copied to /etc/hosts, with the GUESTNAME replaced with the guest's actual name. You can copy your actual /etc/hosts file to clonehosts and edit that.&lt;/div&gt;
&lt;/div&gt;
&lt;pre class="code literal-block"&gt;
127.0.0.1   localhost
127.0.1.1   GUESTNAME

# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
&lt;/pre&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;strong&gt;/usr/local/etc/cloneinterfaces:&lt;/strong&gt;&lt;/div&gt;
&lt;div class="line"&gt;This file will be copied to /etc/network/interfaces, with the GUESTIP replaced with the guest's actual IP address. You can copy your actual /etc/network/interfaces file to cloneinterfaces and edit that.&lt;/div&gt;
&lt;/div&gt;
&lt;pre class="code literal-block"&gt;
# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
auto eth0
iface eth0 inet static
  address GUESTIP
  netmask 255.255.255.0
  gateway 192.168.1.1
&lt;/pre&gt;
&lt;p&gt;I created the configuration script as /usr/local/sbin/cloneconf, and it looks like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/usr/local/sbin/cloneconf:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/bin/sh

echo &amp;quot;GUEST CONFIGURATION AFTER CLONING&amp;quot;
echo

GUESTNAME=&amp;quot;&amp;quot;

if [ &amp;quot;$1&amp;quot; = &amp;quot;&amp;quot; ]; then
  echo -n &amp;quot;What is the hostname of this guest? &amp;quot;
  read GUESTNAME
else
  GUESTNAME=&amp;quot;$1&amp;quot;
fi

GUESTIP=&amp;quot;$(cat /usr/local/etc/cloneaddresses | egrep ^$GUESTNAME  | awk '{print $2}')&amp;quot;

if [ &amp;quot;$GUESTIP&amp;quot; = &amp;quot;&amp;quot; ]; then
  echo &amp;quot;Hostname not found. Available hostnames:&amp;quot;
  echo
  cat /usr/local/etc/cloneaddresses
  exit 1
fi

echo &amp;quot;This script will configure the host with the following settings:&amp;quot;
echo Hostname: $GUESTNAME
echo IP address: $GUESTIP
echo
echo /etc/hostname:
echo $GUESTNAME
echo
echo /etc/hosts:
cat /usr/local/etc/clonehosts | sed -e &amp;quot;s/GUESTNAME/$GUESTNAME/g&amp;quot;
echo
echo /etc/network/interfaces:
cat /usr/local/etc/cloneinterfaces | sed -e &amp;quot;s/GUESTIP/$GUESTIP/g&amp;quot;
echo
echo -n &amp;quot;Are you sure you want to continue [y/N]? &amp;quot;

read YN
if [ &amp;quot;$YN&amp;quot; != &amp;quot;y&amp;quot; ]; then
  echo abort.
  exit 1
fi

echo $GUESTNAME &amp;gt; /etc/hostname
cat /usr/local/etc/clonehosts | sed -e &amp;quot;s/GUESTNAME/$GUESTNAME/g&amp;quot; &amp;gt; /etc/hosts
cat /usr/local/etc/cloneinterfaces | sed -e &amp;quot;s/GUESTIP/$GUESTIP/g&amp;quot; &amp;gt; /etc/network/interfaces
test -f /etc/ssh/ssh_host_dsa_key || dpkg-reconfigure openssh-server

echo
echo Done. The machine will now be rebooted to make changes effective.
echo
for i in 12 11 10 9 8 7 6 5 4 3 2 1; do echo &amp;quot;Rebooting in $i seconds (Ctrl-C to abort)&amp;quot;; sleep 1; done
reboot
&lt;/pre&gt;
&lt;p&gt;Give execute permission with &amp;quot;sudo chmod u+x /usr/local/sbin/cloneconf&amp;quot;.&lt;/p&gt;
&lt;p&gt;That script must be run individually on each cloned guest machine. Either give the hostname as the single argument to the script, or the script will ask you for the hostname if you don't do that. The hostname must be found in the cloneaddresses file. The rest of the settings will be determined from the configuration files.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="part-ii-cloning-and-configuring-multiple-guests-from-your-template"&gt;
&lt;h2&gt;Part II. Cloning and configuring multiple guests from your template&lt;/h2&gt;
&lt;p&gt;Cloning guests from a template is as easy as:&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;Run the &amp;quot;cloneprep&amp;quot; script on the template guest and shut it down&lt;/li&gt;
&lt;li&gt;Clone as many new guests as you wish with the virt-clone command&lt;/li&gt;
&lt;li&gt;Start up each new guest&lt;/li&gt;
&lt;li&gt;Run &amp;quot;cloneconf&amp;quot; on each new guest&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="section" id="clone"&gt;
&lt;h3&gt;Clone&lt;/h3&gt;
&lt;p&gt;One clone:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo virt-clone --original=template1 --name=guest01 --file=/var/lib/libvirt/images/guest01.img
&lt;/pre&gt;
&lt;p&gt;Or a dozen clones:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
for i in {01..12}; do sudo virt-clone -o template1 -n guest$i -f /var/lib/libvirt/images/guest$i.img; done
&lt;/pre&gt;
&lt;p&gt;The virt-clone command will create a new xml configuration file under /etc/libvirt/qemu with a new UUID and randomly selected MAC address. Also, it will copy the image file to the location specified in the command line.&lt;/p&gt;
&lt;p&gt;If you configured your template for serial console operation (link to the instructions in Tip 1 above), you can start up the new guest and get the console instantly using this command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo virsh create /etc/libvirt/qemu/guest01.xml --console
&lt;/pre&gt;
&lt;p&gt;To start your dozen guests simultaneously:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
for i in {01..12}; do sudo virsh create /etc/libvirt/qemu/guest$i.xml; done
&lt;/pre&gt;
&lt;p&gt;Then connect to the console of each individual guest with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo virsh console guest01
&lt;/pre&gt;
&lt;p&gt;You can get a list of running guests with &amp;quot;virsh list&amp;quot;.&lt;/p&gt;
&lt;p&gt;To end a serial console session, press &lt;strong&gt;Ctrl-]&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configure"&gt;
&lt;h3&gt;Configure&lt;/h3&gt;
&lt;p&gt;The cloneconf script created in the first part of this post makes things easy.&lt;/p&gt;
&lt;p&gt;After you have logged into a running guest machine (either VNC, serial console or ssh), run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo cloneconf &amp;lt;hostname&amp;gt;
&lt;/pre&gt;
&lt;p&gt;The hostname must be listed in the /usr/local/etc/cloneaddresses file created earlier. Otherwise the script will abort. It will show you changes it is about to make, and let you choose whether to commit them or not.&lt;/p&gt;
&lt;p&gt;Reboot the guest after the script has run. Repeat for all clones.&lt;/p&gt;
&lt;p&gt;The script will make changes to these files:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;/etc/hostname&lt;/li&gt;
&lt;li&gt;/etc/hosts&lt;/li&gt;
&lt;li&gt;/etc/network/interfaces&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It will replace the hostname and IP address with a suitable value.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="part-iii-conclusions-and-recommendations"&gt;
&lt;h2&gt;Part III. Conclusions and recommendations&lt;/h2&gt;
&lt;p&gt;Customizing each cloned guest really just consists of changing or regenerating the following files:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;/etc/hostname&lt;/li&gt;
&lt;li&gt;/etc/hosts&lt;/li&gt;
&lt;li&gt;/etc/network/interfaces&lt;/li&gt;
&lt;li&gt;/etc/ssh/ssh_host_dsa_key&lt;/li&gt;
&lt;li&gt;/etc/ssh/ssh_host_dsa_key.pub&lt;/li&gt;
&lt;li&gt;/etc/ssh/ssh_host_rsa_key&lt;/li&gt;
&lt;li&gt;/etc/ssh/ssh_host_rsa_key.pub&lt;/li&gt;
&lt;li&gt;/etc/udev/rules.d/70-persistent-net.rules&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that, the rest of the template customization is up to you.&lt;/p&gt;
&lt;p&gt;I recommend creating one master template with the instructions above, with very little installed software - the bare minimum you will install on ALL of your virtual machine guests. Configure all the authentication and NFS stuff, and whatever your environment requires.&lt;/p&gt;
&lt;p&gt;Then clone this master template to create new templates for your web servers, mail servers etc. You can run cloneprep on them again even if you already ran cloneconf, to reverse a cloned guest back to a template (although change /etc/network/interfaces back to DHCP in order to avoid IP address conflicts).&lt;/p&gt;
&lt;p&gt;After all this messing around with templates, deploying a new server is really quick and easy. You will have the right software installed, and nearly configured. And you can even customize the cloneconf script to configure whatever software you like.&lt;/p&gt;
&lt;p&gt;I hope this helps!&lt;/p&gt;
&lt;p&gt;Here you can download the scripts and configuration files in one package: clonetools.tar.gz &lt;em&gt;(download no longer available)&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="KVM"></category><category term="Linux"></category><category term="Ubuntu"></category><category term="Virtualization"></category></entry><entry><title>Serial console for Ubuntu server 10.04 KVM guests</title><link href="https://mikko.kortelainen.io/blog/serial-console-for-ubuntu-server-1004-kvm-guests/" rel="alternate"></link><published>2010-11-27T13:15:00+02:00</published><updated>2010-11-27T13:15:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2010-11-27:/blog/serial-console-for-ubuntu-server-1004-kvm-guests/</id><summary type="html">&lt;p&gt;The virt-manager VNC screen is fine for LAN connections, and good for running
graphical sessions. X is not installed on Ubuntu server by default, and VNC is
really bad over slow links even for text console. I like to configure serial
console for all my virtualized guests, because with it …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The virt-manager VNC screen is fine for LAN connections, and good for running
graphical sessions. X is not installed on Ubuntu server by default, and VNC is
really bad over slow links even for text console. I like to configure serial
console for all my virtualized guests, because with it, I can simply ssh into
the virtual machine host, and run &amp;quot;virsh console &amp;lt;guest-name&amp;gt;&amp;quot; to get a working
console. Very nice for fixing broken network connections or file systems, or any
kind of boot problems. And I can do it using just my cell phone, ssh over 3G
connection from anywhere!&lt;/p&gt;
&lt;p&gt;In Ubuntu, there are three things you may want to configure to use serial console:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;1. GRUB boot menu&lt;/div&gt;
&lt;div class="line"&gt;2. Kernel and init messages&lt;/div&gt;
&lt;div class="line"&gt;3. Pseudo tty to log in and get shell&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="serial-device-for-your-virtual-guest"&gt;
&lt;h2&gt;Serial device for your virtual guest&lt;/h2&gt;
&lt;p&gt;But first things first: you must add a serial device for your guest machine in
order to be able to use the serial console.&lt;/p&gt;
&lt;p&gt;In virt-manager it is as easy as adding a new hardware device, type Serial, and
device type &amp;quot;Pseudo TTY (pty)&amp;quot; into the machine configuration. No further
configuration needed, just add the device and that's it.&lt;/p&gt;
&lt;p&gt;In the libvirt XML configuration file the device should look something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
&amp;lt;serial type='pty'&amp;gt;
  &amp;lt;target port='0'/&amp;gt;
&amp;lt;/serial&amp;gt;
&amp;lt;console type='pty'&amp;gt;
  &amp;lt;target port='0'/&amp;gt;
&amp;lt;/console&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="the-grub-boot-menu-linux-kernel-and-system-init-messages"&gt;
&lt;h2&gt;The GRUB boot menu, Linux kernel, and system init messages&lt;/h2&gt;
&lt;p&gt;With GRUB 1, it was possible to get the GRUB menu simultaneously over serial and
graphical VNC console. Unfortunately I haven't found a way to do that with GRUB
2. Linux kernel fortunately does output messages both to the serial and VNC
console if so configured. The upstart init will output its' messages to whatever
the kernel is configured to do.&lt;/p&gt;
&lt;p&gt;To make the GRUB menu and kernel messages show up over serial console, you need
to edit the /etc/default/grub file and run update-grub afterwards. The changed
or added lines are marked with bold below:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/etc/default/grub:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.

GRUB_DEFAULT=0
GRUB_HIDDEN_TIMEOUT=
GRUB_HIDDEN_TIMEOUT_QUIET=false
GRUB_TIMEOUT=10
GRUB_DISTRIBUTOR=`lsb_release -i -s 2&amp;gt; /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;&amp;quot;
GRUB_CMDLINE_LINUX=&amp;quot;text console=tty0 console=ttyS0,115200n8&amp;quot;

# Uncomment to disable graphical terminal (grub-pc only)
#GRUB_TERMINAL=console
GRUB_TERMINAL=serial
GRUB_SERIAL_COMMAND=&amp;quot;serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1&amp;quot;

# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480

# Uncomment if you don't want GRUB to pass &amp;quot;root=UUID=xxx&amp;quot; parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true

# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_LINUX_RECOVERY=&amp;quot;true&amp;quot;

# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE=&amp;quot;480 440 1&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Run update-grub after making the changes. During the next reboot, you will be
able to choose your kernel using the GRUB menu, or run any grub commands, using
the serial console.&lt;/p&gt;
&lt;p&gt;The GRUB menu will show up only on the serial console, while the kernel and init
messages will show up on both serial console and the graphical screen.&lt;/p&gt;
&lt;div class="section" id="detailed-explanation"&gt;
&lt;h3&gt;Detailed explanation&lt;/h3&gt;
&lt;p&gt;Here's a description of what each of the changes mean:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
GRUB_HIDDEN_TIMEOUT=
&lt;/pre&gt;
&lt;p&gt;This simply enables the GRUB menu, which is hidden by default in Ubuntu.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
GRUB_CMDLINE_LINUX_DEFAULT=&amp;quot;&amp;quot;
GRUB_CMDLINE_LINUX=&amp;quot;text console=tty0 console=ttyS0,115200n8?
&lt;/pre&gt;
&lt;p&gt;These two lines control the Linux kernel behaviour. This will append the
necessary kernel command line options to all kernels, both normal and rescue
mode. With the two console= options, the messages will go to both tty0 (VNC
screen) and ttyS0 (serial console).&lt;/p&gt;
&lt;p&gt;Also upstart init will show messages on both, and single user mode (runlevel 1)
will work on both (the rescue mode root shell).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
GRUB_TERMINAL=serial

GRUB_SERIAL_COMMAND=
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="KVM"></category><category term="Linux"></category><category term="Ubuntu"></category><category term="Virtualization"></category></entry><entry><title>N900 Scandinavic Letters from US keyboard</title><link href="https://mikko.kortelainen.io/blog/n900-scandinavic-letters-from-us-keyboard/" rel="alternate"></link><published>2009-12-20T14:46:00+02:00</published><updated>2009-12-20T14:46:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2009-12-20:/blog/n900-scandinavic-letters-from-us-keyboard/</id><summary type="html">&lt;p&gt;My Nokia N900 has the US keyboard with four arrow keys but no diacritics, two of
which are used in my native Finnish language. I actually like having the four
arrow keys instead of two arrow keys plus dedicated diacritics. You can anyway
get those from the on-screen keyboard, but …&lt;/p&gt;</summary><content type="html">&lt;p&gt;My Nokia N900 has the US keyboard with four arrow keys but no diacritics, two of
which are used in my native Finnish language. I actually like having the four
arrow keys instead of two arrow keys plus dedicated diacritics. You can anyway
get those from the on-screen keyboard, but it is better to remap some of the
hardware keys to be able to punch them in quicker. Here's how.&lt;/p&gt;
&lt;p&gt;To change the default hardware keyboard mapping, edit file
&lt;em&gt;/usr/share/X11/xkb/symbols/nokia_vndr/rx-51&lt;/em&gt;. This file describes the mapping
from hardware keys to symbols on screen. You can change them how you like, but
most of the keys are already mapped with symbols even with the modifier keys
(Ctrl, Alt/Fn, Shift), and the corresponding symbol is printed in the hw button.
So changing those might not be a good idea. However, the arrow keys on the US
keyboard are free to use with the Alt/Fn modifier (the blue northeast pointing
arrow on the left side of the keyboard). The arrow keys with the shift modifier
key are used to select text, though, so they are not to be messed up.&lt;/p&gt;
&lt;p&gt;The last stanza in the file is the &lt;strong&gt;arrows_4btns&lt;/strong&gt;, which can be edited to
provide more symbols directly from the keyboard. My configuration adds four
important (to me) symbols: the letters '&lt;/p&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="Maemo"></category></entry><entry><title>Samba on AIX 5.3</title><link href="https://mikko.kortelainen.io/blog/samba-on-aix-53/" rel="alternate"></link><published>2009-11-12T18:53:00+02:00</published><updated>2009-11-12T18:53:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2009-11-12:/blog/samba-on-aix-53/</id><summary type="html">&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Here are instructions on how to get the pware Samba running on AIX 5.3.&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div class="line"&gt;1. Install these packages from the AIX installation CD:&lt;/div&gt;
&lt;div class="line"&gt;- ldap.client.rte&lt;/div&gt;
&lt;div class="line"&gt;- ldap.client.adt&lt;/div&gt;
&lt;/div&gt;
&lt;ol class="arabic simple" start="2"&gt;
&lt;li&gt;Download these packages:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code literal-block"&gt;
server:root&amp;gt;mkdir pware-samba
server:root&amp;gt;cd pware-samba
server:root&amp;gt;xargs wget -nd &amp;lt;&amp;lt;EOF http://pware.hvcc …&lt;/pre&gt;</summary><content type="html">&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Here are instructions on how to get the pware Samba running on AIX 5.3.&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div class="line"&gt;1. Install these packages from the AIX installation CD:&lt;/div&gt;
&lt;div class="line"&gt;- ldap.client.rte&lt;/div&gt;
&lt;div class="line"&gt;- ldap.client.adt&lt;/div&gt;
&lt;/div&gt;
&lt;ol class="arabic simple" start="2"&gt;
&lt;li&gt;Download these packages:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code literal-block"&gt;
server:root&amp;gt;mkdir pware-samba
server:root&amp;gt;cd pware-samba
server:root&amp;gt;xargs wget -nd &amp;lt;&amp;lt;EOF http://pware.hvcc.edu/download/aix53-64/pware53-64.samba.3.4.2.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.base.5.3.0.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.cyrus-sasl.2.1.22.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.gettext.0.17.0.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.krb5.1.6.3.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.libiconv.1.13.1.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.ncurses.5.7.0.1.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.openldap.2.4.19.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.openssl.0.9.8.11.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.popt.1.10.4.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.bdb.4.7.25.4.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.rsync.3.0.6.0.bff.gz http://pware.hvcc.edu/download/aix53-64/pware53-64.zlib.1.2.3.0.bff.gz EOF
server:root&amp;gt;for i in *.gz; do gunzip $i; done
&lt;/pre&gt;
&lt;p&gt;From: &lt;a class="reference external" href="http://pware.hvcc.edu/download/aix53-64/"&gt;http://pware.hvcc.edu/download/aix53-64/&lt;/a&gt;&lt;/p&gt;
&lt;ol class="arabic simple" start="3"&gt;
&lt;li&gt;Install the packages.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The installed files go under &lt;em&gt;/opt/pware64&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Samba configuration file is &lt;em&gt;/opt/pware64/lib/smb.conf&lt;/em&gt;&lt;/p&gt;
&lt;ol class="arabic simple" start="4"&gt;
&lt;li&gt;Extremely simple Samba configuration file:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code literal-block"&gt;
[global]
  workgroup = MYGROUP
  log file = /var/log/%m.log
  max log size = 500

[myshare]
  comment = Sample share
  path = /tmp/myshare
  public = yes
  writable = yes
  browseable = yes
&lt;/pre&gt;
&lt;ol class="arabic simple" start="5"&gt;
&lt;li&gt;Enable POSIX Asynchronous IO if needed:&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code literal-block"&gt;
server:root&amp;gt;mkdev -l posix_aio0
posix_aio0 Available
server:root&amp;gt;lsdev -Cc posix_aio
posix_aio0 Available  Posix Asynchronous I/O
&lt;/pre&gt;
&lt;p&gt;The posix_aio device is needed, otherwise all binaries will complain somewhat like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
exec(): 0509-036 Cannot load program ./smbclient because of the following errors:
        0509-130 Symbol resolution failed for /usr/lib/libc.a[posix_aio_64.o] because:
        0509-136   Symbol _posix_kaio_rdwr64 (number 2) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_listio64 (number 3) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_acancel64 (number 4) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_iosuspend64 (number 5) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_aio_nwait (number 6) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_aio_nwait64 (number 7) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_aio_nwait_timeout (number 8) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_aio_nwait_timeout64 (number 9) is not exported from
                   dependent module /unix.
        0509-136   Symbol _posix_iofsync64 (number 10) is not exported from
                   dependent module /unix.
        0509-026 System error: Error 0
        0509-192 Examine .loader section symbols with the
                 'dump -Tv' command.
&lt;/pre&gt;
&lt;p&gt;So if you run into this error message, create the POSIX AIO device.&lt;/p&gt;
&lt;ol class="arabic simple" start="6"&gt;
&lt;li&gt;Run samba&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code literal-block"&gt;
server:root&amp;gt;/opt/pware64/sbin/smbd
server:root&amp;gt;/opt/pware64/sbin/nmbd
&lt;/pre&gt;
&lt;ol class="arabic simple" start="7"&gt;
&lt;li&gt;Add to inittab for automatic start at boot time&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="code literal-block"&gt;
server:root&amp;gt;mkitab nmbd:2:once:/opt/pware64/sbin/nmbd
server:root&amp;gt;mkitab smbd:2:once:/opt/pware64/sbin/smbd
&lt;/pre&gt;
&lt;div class="section" id="links"&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://pware.hvcc.edu/"&gt;http://pware.hvcc.edu/&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://pware.hvcc.edu/AIX-Samba.pdf"&gt;http://pware.hvcc.edu/AIX-Samba.pdf&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://pware.hvcc.edu/download/"&gt;http://pware.hvcc.edu/download/&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://www.ibm.com/developerworks/aix/library/au-aix_samba/index.html"&gt;http://www.ibm.com/developerworks/aix/library/au-aix_samba/index.html&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="AIX"></category><category term="Samba"></category><category term="UNIX"></category></entry><entry><title>NIC bonding with Red Hat/CentOS</title><link href="https://mikko.kortelainen.io/blog/nic-bonding-with-red-hatcentos/" rel="alternate"></link><published>2009-10-21T17:17:00+03:00</published><updated>2009-10-21T17:17:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2009-10-21:/blog/nic-bonding-with-red-hatcentos/</id><summary type="html">&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Here are simple instructions on how to configure network interface bonding on Red Hat based distros. The thing I always forget. There's also a little script which will create a bonding interface bond0 between eth0 and eth1 and migrate existing IP settings from eth0. You can find it in the …&lt;/div&gt;&lt;/div&gt;</summary><content type="html">&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Here are simple instructions on how to configure network interface bonding on Red Hat based distros. The thing I always forget. There's also a little script which will create a bonding interface bond0 between eth0 and eth1 and migrate existing IP settings from eth0. You can find it in the bottom of this post.&lt;/div&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;But first here's how to do it by hand.&lt;/p&gt;
&lt;p&gt;Configure bonding module and interface alias:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/etc/modprobe.conf:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
alias bond0 bonding
options bond0 miimon=100 mode=1
&lt;/pre&gt;
&lt;p&gt;Insert bonding module:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# modprobe bonding
&lt;/pre&gt;
&lt;p&gt;Configure network interfaces, two physical and one bonding interface:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;/etc/sysconfig/network-scripts/ifcfg-eth0:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
DEVICE=eth0
BOOTPROTO=static
HWADDR=00:11:22:33:44:55
ONBOOT=yes
TYPE=Ethernet
SLAVE=yes
MASTER=bond0
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;/etc/sysconfig/network-scripts/ifcfg-eth1:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
DEVICE=eth1
BOOTPROTO=static
HWADDR=00:11:22:33:44:56
ONBOOT=yes
TYPE=Ethernet
SLAVE=yes
MASTER=bond0
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;/etc/sysconfig-network-scripts/ifcfg-bond0:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
DEVICE=bond0
BOOTPROTO=none
IPADDR=192.168.0.2
NETMASK=255.255.255.0
GATEWAY=192.168.0.1
ONBOOT=yes
&lt;/pre&gt;
&lt;p&gt;Restart networking (your network connections will drop at this point):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# /etc/init.d/network restart
&lt;/pre&gt;
&lt;p&gt;That's it!&lt;/p&gt;
&lt;div class="section" id="automatic-script"&gt;
&lt;h2&gt;Automatic Script&lt;/h2&gt;
&lt;p&gt;Here's the script I promised. It takes your existing IP settings from eth0 and migrates them to a newly created bond0 which is created between eth0 and eth1:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cat &amp;gt;&amp;gt;/etc/modprobe.conf &amp;lt;&amp;lt;EOF
alias bond0 bonding
options bond0 miimon=100 mode=1
EOF

cat &amp;gt;&amp;gt;/etc/sysconfig/network-scripts/ifcfg-bond0 &amp;lt;&amp;lt;EOF
DEVICE=bond0
BOOTPROTO=none
ONBOOT=yes
EOF

cat /etc/sysconfig/network-scripts/ifcfg-eth0 | \
  egrep 'IPADDR|NETMASK|GATEWAY' &amp;gt;&amp;gt;/etc/sysconfig/network-scripts/ifcfg-bond0

HWADDR_ETH0=&amp;quot;$(cat /etc/sysconfig/network-scripts/ifcfg-eth0 | grep HWADDR)&amp;quot;
HWADDR_ETH1=&amp;quot;$(cat /etc/sysconfig/network-scripts/ifcfg-eth1 | grep HWADDR)&amp;quot;

cat &amp;gt; /etc/sysconfig/network-scripts/ifcfg-eth0 &amp;lt;&amp;lt;EOF
DEVICE=eth0
BOOTPROTO=static
ONBOOT=yes
TYPE=Ethernet
SLAVE=yes
MASTER=bond0
$HWADDR_ETH0
EOF

cat &amp;gt; /etc/sysconfig/network-scripts/ifcfg-eth1 &amp;lt;&amp;lt;EOF
DEVICE=eth1
BOOTPROTO=static
ONBOOT=yes
TYPE=Ethernet
SLAVE=yes
MASTER=bond0
$HWADDR_ETH1
EOF
&lt;/pre&gt;
&lt;p&gt;More information can be found in the bonding.txt of the kernel source documentation.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.netmite.com/android/mydroid/kernel/Documentation/networking/bonding.txt"&gt;http://www.netmite.com/android/mydroid/kernel/Documentation/networking/bonding.txt&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="CentOS"></category><category term="Linux"></category><category term="Networking"></category><category term="Red Hat"></category></entry><entry><title>Redundant iSCSI storage for Linux</title><link href="https://mikko.kortelainen.io/blog/redundant-iscsi-storage-for-linux/" rel="alternate"></link><published>2009-06-10T18:14:00+03:00</published><updated>2009-06-10T18:14:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2009-06-10:/blog/redundant-iscsi-storage-for-linux/</id><summary type="html">&lt;p&gt;Here's how to set up relatively cheap redundant iSCSI storage on Linux. The
redundancy is achieved using LVM mirroring, and the storage servers consist of
commodity hardware, running the OpenFiler Linux distribution, which expose their
disks to the clients using iSCSI over Ethernet. The servers are completely
separate entities, and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's how to set up relatively cheap redundant iSCSI storage on Linux. The
redundancy is achieved using LVM mirroring, and the storage servers consist of
commodity hardware, running the OpenFiler Linux distribution, which expose their
disks to the clients using iSCSI over Ethernet. The servers are completely
separate entities, and the purpose of this mirroring is to keep the logical
volumes available, even while one of the storage servers is down for maintenance
or due to hardware failure.&lt;/p&gt;
&lt;p&gt;Ultimately the disks of the iSCSI target servers will show up as normal SCSI
disks on the client (/dev/sdb, /dev/sdc, ...). The data will be moved across the
network transparently. It is preferable to use multiple gigabit network
interface cards on both the initiator and the target, and bond them together for
reliability and speed gain (or use Device Mapper Multipath). A separate VLAN for
iSCSI traffic is recommended for security and speed. By default, the traffic is
not encrypted so your disk blocks can easily be sniffed using tcpdump.&lt;/p&gt;
&lt;p&gt;I created identical logical volumes on both OpenFiler servers and mapped them to
iSCSI targets. The iSCSI initiator (client) here is an Ubuntu 9.04 desktop.&lt;/p&gt;
&lt;div class="section" id="install-open-iscsi-and-map-targets"&gt;
&lt;h2&gt;Install Open-iSCSI and map targets&lt;/h2&gt;
&lt;p&gt;On the client, install Open-iSCSI.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
aptitude install open-iscsi
&lt;/pre&gt;
&lt;p&gt;Run the discovery to see available targets (the IP address is the address of one
of the servers).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
iscsiadm -m discovery -t st -p 192.168.1.115
&lt;/pre&gt;
&lt;p&gt;You should get a target list as the output.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
192.168.1.115:3260,1 iqn.2006-01.com.openfiler:linuxtest1lv
&lt;/pre&gt;
&lt;p&gt;Map the target to a SCSI disk.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
iscsiadm -m node -T iqn.2006-01.com.openfiler:linuxtest1lv -p 192.168.1.115 --login
&lt;/pre&gt;
&lt;p&gt;dmesg should now show a that a new SCSI disk was detected.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[600584.938727] scsi 2:0:0:0: Direct-Access     OPNFILER VIRTUAL-DISK     0    PQ: 0 ANSI: 4
[600584.947903] sd 2:0:0:0: [sdb] 4194304 512-byte hardware sectors: (2.14 GB/2.00 GiB)
[600584.983070] sd 2:0:0:0: [sdb] Write Protect is off
[600584.983074] sd 2:0:0:0: [sdb] Mode Sense: 77 00 00 08
[600584.988064] sd 2:0:0:0: [sdb] Write cache: disabled, read cache: disabled, doesn't support DPO or FUA
[600584.989379] sd 2:0:0:0: [sdb] 4194304 512-byte hardware sectors: (2.14 GB/2.00 GiB)
[600584.989974] sd 2:0:0:0: [sdb] Write Protect is off
[600584.989977] sd 2:0:0:0: [sdb] Mode Sense: 77 00 00 08
[600584.991359] sd 2:0:0:0: [sdb] Write cache: disabled, read cache: disabled, doesn't support DPO or FUA
[600584.991363]  sdb: unknown partition table
[600585.008012] sd 2:0:0:0: [sdb] Attached SCSI disk
[600585.008072] sd 2:0:0:0: Attached scsi generic sg2 type 0
&lt;/pre&gt;
&lt;p&gt;You can now use the disk as a normal SCSI disk.&lt;/p&gt;
&lt;p&gt;Discover the second storage server.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
iscsiadm -m discovery -t st -p 192.168.1.120
&lt;/pre&gt;
&lt;p&gt;Target found:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
192.168.1.120:3260,1 iqn.2006-01.com.openfiler:linuxtest1lv-2
&lt;/pre&gt;
&lt;p&gt;Map the target.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
iscsiadm -m node -T iqn.2006-01.com.openfiler:linuxtest1lv-2 192.168.1.120 --login
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="make-persistent-across-reboots"&gt;
&lt;h2&gt;Make persistent across reboots&lt;/h2&gt;
&lt;p&gt;The discovered nodes will automatically show up under &lt;em&gt;/etc/iscsi/nodes&lt;/em&gt;. If you
wish to make them available automatically after reboot, change the following
line in the corresponding node file:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
node.conn[0].startup = manual
&lt;/pre&gt;
&lt;p&gt;Change to:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
node.conn[0].startup = automatic
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="partition-with-fdisk-optional"&gt;
&lt;h2&gt;Partition with fdisk (optional)&lt;/h2&gt;
&lt;p&gt;I partitioned the disks with fdisk. This is optional, but I like to do it
because it makes easier to detect the type of the disk just by checking the
partition table.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Disk /dev/sdb: 2147 MB, 2147483648 bytes
67 heads, 62 sectors/track, 1009 cylinders
Units = cylinders of 4154 * 512 = 2126848 bytes
Disk identifier: 0x32d429c4

   Device Boot      Start         End      Blocks   Id  System
/dev/sdb1               1        1009     2095662   8e  Linux LVM

Disk /dev/sdc: 2147 MB, 2147483648 bytes
67 heads, 62 sectors/track, 1009 cylinders
Units = cylinders of 4154 * 512 = 2126848 bytes
Disk identifier: 0x9823ed68

   Device Boot      Start         End      Blocks   Id  System
/dev/sdc1               1        1009     2095662   8e  Linux LVM
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="the-lvm-part"&gt;
&lt;h2&gt;The LVM Part&lt;/h2&gt;
&lt;p&gt;Install Logical Volume Manager.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
aptitude install lvm2
&lt;/pre&gt;
&lt;p&gt;Create physical volumes and the volume group.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
pvcreate /dev/sdb1
pvcreate /dev/sdc1
vgcreate vg0 /dev/sdb1 /dev/sdc1
&lt;/pre&gt;
&lt;p&gt;Create a mirrored logical volume.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
lvcreate --mirrors 1 --corelog --name testlv --size 512M vg0
&lt;/pre&gt;
&lt;p&gt;Create filesystem and mount.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mke2fs -j /dev/vg0/testlv
mount /dev/vg0/testlv /mnt/test
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="speed"&gt;
&lt;h2&gt;Speed&lt;/h2&gt;
&lt;p&gt;Test read speeds.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
hdparm -t /dev/mapper/vg0-testlv
&lt;/pre&gt;
&lt;p&gt;10 MB per second is about the max I can get with this test system which uses 100
Mbit/s ethernet.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/dev/mapper/vg0-testlv:
 Timing buffered disk reads:   32 MB in  3.22 seconds =   9.95 MB/sec
&lt;/pre&gt;
&lt;p&gt;On a production system, gigabit is a must (preferably multiple links bonded).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="status-of-the-mirrored-logical-volume"&gt;
&lt;h2&gt;Status of the Mirrored Logical Volume&lt;/h2&gt;
&lt;p&gt;To check the status of the mirrored logical volume, run the command &amp;quot;lvs&amp;quot;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
LV     VG   Attr   LSize   Origin Snap%  Move Log Copy%  Convert
testlv vg0  mwi-ao 512,00M                        100,00
&lt;/pre&gt;
&lt;p&gt;The Copy% will show the percentage of copied extents. 100% indicates the mirrors
are synced. Whenever a mirror is out-of-sync and is being updated, the
percentage will be less.&lt;/p&gt;
&lt;p&gt;The commands &amp;quot;lvdisplay -m&amp;quot; and &amp;quot;pvdisplay -m&amp;quot; will show you a detailed map of
the extents on the physical volumes:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;lvdisplay -m&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
--- Logical volume ---
LV Name                /dev/vg0/testlv
VG Name                vg0
LV UUID                5ookbu-qJ9h-rzBA-D6Ek-mkH2-Vryc-EYYqvp
LV Write Access        read/write
LV Status              available
# open                 1
LV Size                512,00 MB
Current LE             128
Segments               1
Allocation             inherit
Read ahead sectors     auto
- currently set to     256
Block device           252:2

--- Segments ---
Logical extent 0 to 127:
  Type        mirror
  Mirrors     2
  Mirror size     128
  Mirror region size  512,00 KB
  Mirror original:
    Logical volume    testlv_mimage_0
    Logical extents   0 to 127
  Mirror destinations:
    Logical volume    testlv_mimage_1
    Logical extents   0 to 127
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;pvdisplay -m&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
--- Physical volume ---
PV Name               /dev/sdb1
VG Name               vg0
PV Size               2,00 GB / not usable 2,54 MB
Allocatable           yes
PE Size (KByte)       4096
Total PE              511
Free PE               383
Allocated PE          128
PV UUID               JINpaF-WiCp-sEH2-2PcK-bEvR-ht8j-mRAg05

--- Physical Segments ---
Physical extent 0 to 127:
  Logical volume  /dev/vg0/testlv_mimage_0
  Logical extents 0 to 127
Physical extent 128 to 510:
  FREE

--- Physical volume ---
PV Name               /dev/sdc1
VG Name               vg0
PV Size               2,00 GB / not usable 2,54 MB
Allocatable           yes
PE Size (KByte)       4096
Total PE              511
Free PE               383
Allocated PE          128
PV UUID               V7dMTV-gWLe-gRWy-H7LU-7mwI-LsBu-2uIC7C

--- Physical Segments ---
Physical extent 0 to 127:
  Logical volume  /dev/vg0/testlv_mimage_1
  Logical extents 0 to 127
Physical extent 128 to 510:
  FREE
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="testing-for-failure"&gt;
&lt;h2&gt;Testing for failure&lt;/h2&gt;
&lt;p&gt;When the other iSCSI server was brought down, it took about two minutes before
the iSCSI initiator gave up. After this, the mounted volume was working without
problems. During the two-minute timeout countdown, some slowness and waiting was
experienced.&lt;/p&gt;
&lt;p&gt;After the iSCSI server was brought up again, the other half of the mirror was
restored and synced automatically. In conclusion, I would say my mirrored
logical volume can be thought of as highly available.&lt;/p&gt;
&lt;p&gt;It seems that the timeout value can be set in the node configuration file
(although I didn't test it):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
node.session.timeo.replacement_timeout = 120
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="links-and-references"&gt;
&lt;h2&gt;Links and references&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://openfiler.com/"&gt;http://openfiler.com/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.open-iscsi.org/"&gt;http://www.open-iscsi.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.howtoforge.com/iscsi_on_linux"&gt;http://www.howtoforge.com/iscsi_on_linux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="iSCSI"></category><category term="Linux"></category><category term="OpenFiler"></category><category term="Storage"></category><category term="Ubuntu"></category></entry><entry><title>Differential Xcopy parameters</title><link href="https://mikko.kortelainen.io/blog/differential-xcopy-parameters/" rel="alternate"></link><published>2009-04-15T17:17:00+03:00</published><updated>2009-04-15T17:17:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2009-04-15:/blog/differential-xcopy-parameters/</id><summary type="html">&lt;p&gt;I always forget what the correct options for the Windows xcopy command are when I simply want to synchronize one directory over another one, so that only changed files are overwritten. To do it well, you need to remember too many options. And robocopy is never installed when you need …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I always forget what the correct options for the Windows xcopy command are when I simply want to synchronize one directory over another one, so that only changed files are overwritten. To do it well, you need to remember too many options. And robocopy is never installed when you need it.&lt;/p&gt;
&lt;p&gt;Here it is:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
xcopy /keychord source destination
&lt;/pre&gt;
&lt;p&gt;The options:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/k copy attributes
/e be recursive, and even re-create empty directories
/y say yes to prompts
/c don't stop on errors
/h copy hidden and system files
/o copy ownership and ACL information
/r overwrite read-only files
/d copy only changed files (or new files)
&lt;/pre&gt;
&lt;p&gt;Just remember, &amp;quot;Key Chord&amp;quot;&lt;/p&gt;
</content><category term="Blog"></category><category term="Windows"></category></entry><entry><title>OpenSSH public key authentication</title><link href="https://mikko.kortelainen.io/blog/openssh-public-key-authentication/" rel="alternate"></link><published>2009-01-09T18:11:00+02:00</published><updated>2009-01-09T18:11:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2009-01-09:/blog/openssh-public-key-authentication/</id><summary type="html">&lt;p&gt;First, create a key-pair with &lt;a class="reference external" href="http://www.openbsd.org/cgi-bin/man.cgi?query=ssh-keygen"&gt;ssh-keygen&lt;/a&gt;. This is a one-time operation.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ssh-keygen -t dsa
&lt;/pre&gt;
&lt;p&gt;It is good practice to enter a good password, but you may also leave the password empty. That will leave your private key vulnerable to local attacks, but if you need to login somewhere from a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;First, create a key-pair with &lt;a class="reference external" href="http://www.openbsd.org/cgi-bin/man.cgi?query=ssh-keygen"&gt;ssh-keygen&lt;/a&gt;. This is a one-time operation.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ssh-keygen -t dsa
&lt;/pre&gt;
&lt;p&gt;It is good practice to enter a good password, but you may also leave the password empty. That will leave your private key vulnerable to local attacks, but if you need to login somewhere from a cron job, you probably need to do that.&lt;/p&gt;
&lt;p&gt;For interactive logins, it is better to use &lt;a class="reference external" href="http://www.openbsd.org/cgi-bin/man.cgi?query=ssh-agent"&gt;ssh-agent&lt;/a&gt;.&lt;/p&gt;
&lt;div class="section" id="copy-your-public-key-to-the-server"&gt;
&lt;h2&gt;Copy your public key to the server&lt;/h2&gt;
&lt;p&gt;Newer distributions have the &lt;a class="reference external" href="http://linux.die.net/man/1/ssh-copy-id"&gt;ssh-copy-id&lt;/a&gt; command, which makes copying your key as easy as:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ssh-copy-id remoteserver
&lt;/pre&gt;
&lt;p&gt;If you don't have ssh-copy-id, you must manually append your public key to the &amp;quot;.ssh/authorized_keys&amp;quot; file under your home directory on the remote host. This does just that:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cat ~/.ssh/id_dsa.pub | ssh remoteserver 'cat &amp;gt;&amp;gt;.ssh/authorized_keys'
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="server-side-sshd-configuration"&gt;
&lt;h2&gt;Server side sshd configuration&lt;/h2&gt;
&lt;p&gt;This is what you need in &amp;quot;/etc/ssh/sshd_config&amp;quot; for public key authentication to work in the first place:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
&lt;/pre&gt;
&lt;p&gt;A restart is required if you changed anything.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="allowing-root-to-log-in-with-rsa-dsa-keys"&gt;
&lt;h2&gt;Allowing root to log in with RSA/DSA keys&lt;/h2&gt;
&lt;p&gt;To enable public key authentication as root, the &amp;quot;PermitRootLogin&amp;quot; configuration setting must not be set to &amp;quot;no&amp;quot;. In other words, it should either be set to:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
PermitRootLogin yes
&lt;/pre&gt;
&lt;p&gt;or the way I prefer it:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
PermitRootLogin without-password
&lt;/pre&gt;
&lt;p&gt;The latter form will disallow root login with a password, but allow it with a key. Makes brute force root password guessing impossible.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="slow-authentication"&gt;
&lt;h2&gt;Slow authentication&lt;/h2&gt;
&lt;p&gt;If login takes a long time (more than about 5 seconds), make sure ssh does not try to make a reverse lookup for the remote host IP address. You will not detect this unless you yank the &amp;quot;LogLevel&amp;quot; to &amp;quot;Debug&amp;quot; and restart ssh. After that, you will see messages like this while the client is waiting for login:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Jan  9 14:47:31 localhost sshd[26374]: debug3: Trying to reverse map address 192.168.0.1.
&lt;/pre&gt;
&lt;p&gt;There are two things that may cause the reverse lookups. The first is a configuration file option in &amp;quot;/etc/ssh/sshd_config&amp;quot; called &amp;quot;VerifyReverseMapping&amp;quot;. It should be set to &amp;quot;no&amp;quot;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
VerifyReverseMapping no
&lt;/pre&gt;
&lt;p&gt;That is also the default setting, so it is less likely to be the real reason for reverse lookups. The following one is the more likely one.&lt;/p&gt;
&lt;p&gt;The second thing that may cause OpenSSH to do reverse lookups is that by default it will try to store the remote hostname in utmp. To disable this, it needs the option &amp;quot;-u0&amp;quot; on the command line.&lt;/p&gt;
&lt;p&gt;On Red Hat(ish) systems you can do this easily by adding the following option to the &amp;quot;/etc/sysconfig/sshd&amp;quot; file:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
OPTIONS=&amp;quot;-u0&amp;quot;
&lt;/pre&gt;
&lt;p&gt;On Ubuntu, add this to &amp;quot;/etc/default/ssh&amp;quot;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
SSHD_OPTS=&amp;quot;-u0&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Restart sshd, and you will have a faster login. This setting will also speed up logins when the reverse lookups do work, because they will in any case slow down the authentication process.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="OpenSSH"></category></entry><entry><title>Ubuntu 8.10 on Thinkpad X300</title><link href="https://mikko.kortelainen.io/blog/ubuntu-810-on-thinkpad-x300/" rel="alternate"></link><published>2008-12-08T23:22:00+02:00</published><updated>2008-12-08T23:22:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-12-08:/blog/ubuntu-810-on-thinkpad-x300/</id><summary type="html">&lt;p&gt;I upgraded my Lenovo Thinkpad X300 to Ubuntu 8.10 Intrepid Ibex today. My original installation notes for Hardy are &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/lenovo-thinkpad-x300-ubuntu-804-installation-notes/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After the upgrade, sound was working without compiling an ALSA snapshot by hand. Also, 3G connections worked straight out of the NetworkManager applet, which is very nice. But WiFi …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I upgraded my Lenovo Thinkpad X300 to Ubuntu 8.10 Intrepid Ibex today. My original installation notes for Hardy are &lt;a class="reference external" href="https://mikko.kortelainen.io/blog/lenovo-thinkpad-x300-ubuntu-804-installation-notes/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After the upgrade, sound was working without compiling an ALSA snapshot by hand. Also, 3G connections worked straight out of the NetworkManager applet, which is very nice. But WiFi was broken, as the nm-applet refused to connect to any SSID, encrypted or open. That seemed to be due to myself using the development networkmanager packages with Hardy. They were not upgraded correctly. The remedy was to remove all network-manager packages and reinstall them.&lt;/p&gt;
&lt;p&gt;The xorg.conf mouse settings don't work on 8.10 anymore. Instead, HAL needs to be configured like this. Create file &amp;quot;/etc/hal/fdi/policy/mouse-wheel.fdi&amp;quot; with the following content:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
&amp;lt;match key=&amp;quot;info.product&amp;quot; string=&amp;quot;TPPS/2 IBM TrackPoint&amp;quot;&amp;gt;
 &amp;lt;merge key=&amp;quot;input.x11_options.EmulateWheel&amp;quot; type=&amp;quot;string&amp;quot;&amp;gt;true&amp;lt;/merge&amp;gt;
 &amp;lt;merge key=&amp;quot;input.x11_options.EmulateWheelButton&amp;quot; type=&amp;quot;string&amp;quot;&amp;gt;2&amp;lt;/merge&amp;gt;
 &amp;lt;merge key=&amp;quot;input.x11_options.YAxisMapping&amp;quot; type=&amp;quot;string&amp;quot;&amp;gt;4 5&amp;lt;/merge&amp;gt;
 &amp;lt;merge key=&amp;quot;input.x11_options.XAxisMapping&amp;quot; type=&amp;quot;string&amp;quot;&amp;gt;6 7&amp;lt;/merge&amp;gt;
 &amp;lt;merge key=&amp;quot;input.x11_options.Emulate3Buttons&amp;quot; type=&amp;quot;string&amp;quot;&amp;gt;true&amp;lt;/merge&amp;gt;
 &amp;lt;merge key=&amp;quot;input.x11_options.EmulateWheelTimeout&amp;quot; type=&amp;quot;string&amp;quot;&amp;gt;200&amp;lt;/merge&amp;gt;
&amp;lt;/match&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Reboot the computer, and you should have middle button scrolling working as always. Here's the link: &lt;a class="reference external" href="http://www.thinkwiki.org/wiki/How_to_configure_the_TrackPoint#TrackPoint_under_Ubuntu_8.10_using_HAL"&gt;http://www.thinkwiki.org/wiki/How_to_configure_the_TrackPoint#TrackPoint_under_Ubuntu_8.10_using_HAL&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you want to upgrade to OpenOffice.org 3.0, here's a nice howto:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://forums.ubuntu.com.my/viewtopic.php?f=42&amp;amp;t=616"&gt;http://forums.ubuntu.com.my/viewtopic.php?f=42&amp;amp;t=616&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;VMWare Workstation 6.5 worked pretty much fine after the upgrade. The modules were compiled correctly. The only annoyance was that some keyboard keys seem to be mapped in a wrong way (perhaps something to do with the new X server version). Anyway, there's the fix: &lt;a class="reference external" href="http://communities.vmware.com/thread/177133"&gt;http://communities.vmware.com/thread/177133&lt;/a&gt;. All you need to do i add the following key mappings to /etc/vmware/config and restart:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
xkeymap.keycode.108 = 0x138 # Alt_R
xkeymap.keycode.106 = 0x135 # KP_Divide
xkeymap.keycode.104 = 0x11c # KP_Enter
xkeymap.keycode.111 = 0x148 # Up
xkeymap.keycode.116 = 0x150 # Down
xkeymap.keycode.113 = 0x14b # Left
xkeymap.keycode.114 = 0x14d # Right
xkeymap.keycode.105 = 0x11d # Control_R
xkeymap.keycode.118 = 0x152 # Insert
xkeymap.keycode.119 = 0x153 # Delete
xkeymap.keycode.110 = 0x147 # Home
xkeymap.keycode.115 = 0x14f # End
xkeymap.keycode.112 = 0x149 # Prior
xkeymap.keycode.117 = 0x151 # Next
xkeymap.keycode.78 = 0x46 # Scroll_Lock
xkeymap.keycode.127 = 0x100 # Pause
xkeymap.keycode.133 = 0x15b # Meta_L
xkeymap.keycode.134 = 0x15c # Meta_R
xkeymap.keycode.135 = 0x15d # Menu
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="ThinkPad"></category><category term="Ubuntu"></category></entry><entry><title>Installing PHP 5 on AIX using IBM HTTP Server</title><link href="https://mikko.kortelainen.io/blog/installing-php-5-on-aix-using-ibm-http-server/" rel="alternate"></link><published>2008-12-08T16:48:00+02:00</published><updated>2008-12-08T16:48:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-12-08:/blog/installing-php-5-on-aix-using-ibm-http-server/</id><summary type="html">&lt;p&gt;I was not able to compile PHP 5.2.6 with IBM HTTP Server 6.1 as a module, so I compiled it as a CGI binary instead. Here's how to do it.&lt;/p&gt;
&lt;div class="section" id="download-the-aix-toolbox-from"&gt;
&lt;h2&gt;1. Download the AIX toolbox from:&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="ftp://ftp.software.ibm.com/aix/freeSoftware/aixtoolbox/RPMS/ppc/"&gt;ftp://ftp.software.ibm.com/aix/freeSoftware/aixtoolbox/RPMS/ppc/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You …&lt;/p&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I was not able to compile PHP 5.2.6 with IBM HTTP Server 6.1 as a module, so I compiled it as a CGI binary instead. Here's how to do it.&lt;/p&gt;
&lt;div class="section" id="download-the-aix-toolbox-from"&gt;
&lt;h2&gt;1. Download the AIX toolbox from:&lt;/h2&gt;
&lt;p&gt;&lt;a class="reference external" href="ftp://ftp.software.ibm.com/aix/freeSoftware/aixtoolbox/RPMS/ppc/"&gt;ftp://ftp.software.ibm.com/aix/freeSoftware/aixtoolbox/RPMS/ppc/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You don't need to download everything, but that is the easiest way. The whole toolbox is about 2.8 GB in size. If you have wget, just say:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
wget ftp://ftp.software.ibm.com/aix/freeSoftware/aixtoolbox/RPMS/ppc/
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="install-gcc-and-the-rest-of-the-gnu-toolchain"&gt;
&lt;h2&gt;2. Install GCC and the rest of the GNU toolchain&lt;/h2&gt;
&lt;p&gt;Go to the toolbox dir and run the following command.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
xargs rpm -iv &amp;lt;&amp;lt; EOF
autoconf/autoconf-2.59-1.aix5.1.noarch.rpm
automake/automake-1.8.5-1.aix5.1.noarch.rpm
binutils/binutils-2.14-3.aix5.1.ppc.rpm
gcc/gcc-4.2.0-3.aix5.3.ppc.rpm
gcc/gcc-cplusplus-4.2.0-3.aix5.3.ppc.rpm
gcc/gcc-locale-4.2.0-3.aix5.3.ppc.rpm
gcc/libgcc-4.2.0-3.aix5.3.ppc.rpm
gcc/libstdcplusplus-4.2.0-3.aix5.3.ppc.rpm
gcc/libstdcplusplus-devel-4.2.0-3.aix5.3.ppc.rpm
gdbm/gdbm-1.8.3-2.aix5.1.ppc.rpm
gdbm/gdbm-devel-1.8.3-2.aix5.1.ppc.rpm
libtool/libtool-1.5.8-2.aix5.1.ppc.rpm
m4/m4-1.4.1-1.aix5.1.ppc.rpm
make/make-3.80-1.aix5.1.ppc.rpm
EOF
&lt;/pre&gt;
&lt;p&gt;You will probably want to replace the package names with the newest versions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="install-php-5-prerequisites"&gt;
&lt;h2&gt;3. Install PHP 5 prerequisites&lt;/h2&gt;
&lt;p&gt;In the same toolbox dir, run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
xargs rpm -iv &amp;lt;&amp;lt; EOF
bzip2/bzip2-1.0.2-4.aix5.1.ppc.rpm
gd/gd-1.8.4-3.aix5.1.ppc.rpm
gd/gd-devel-1.8.4-3.aix5.1.ppc.rpm
gd/gd-progs-1.8.4-3.aix5.1.ppc.rpm
gettext/gettext-0.10.40-8.aix5.2.ppc.rpm
libpng/libpng-1.2.8-8.aix5.2.ppc.rpm
libpng/libpng-devel-1.2.8-8.aix5.2.ppc.rpm
libjpeg/libjpeg-6b-6.aix5.1.ppc.rpm
libjpeg/libjpeg-devel-6b-6.aix5.1.ppc.rpm
freetype/freetype-1.3.1-9.aix5.1.ppc.rpm
freetype/freetype-devel-1.3.1-9.aix5.1.ppc.rpm
freetype2/freetype2-2.1.7-5.aix5.1.ppc.rpm
freetype2/freetype2-devel-2.1.7-5.aix5.1.ppc.rpm
libxml2/libxml2-2.6.21-3.aix5.2.ppc.rpm
libxml2/libxml2-devel-2.6.21-3.aix5.2.ppc.rpm
zlib/zlib-1.2.3-4.aix5.2.ppc.rpm
zlib/zlib-devel-1.2.3-4.aix5.2.ppc.rpm
EOF
&lt;/pre&gt;
&lt;p&gt;This really depends on what you want to compile in. My settings will require the stuff listed above.&lt;/p&gt;
&lt;p&gt;Also, install fileset &lt;em&gt;bos.adt.libm&lt;/em&gt; from the AIX installation media.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="download-and-unpack-the-latest-php-5"&gt;
&lt;h2&gt;4. Download and unpack the latest PHP 5&lt;/h2&gt;
&lt;p&gt;Download the latest version from:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.php.net/downloads.php#v5"&gt;http://www.php.net/downloads.php#v5&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I downloaded 5.2.6. Unpack:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
gunzip php-5.2.6.tar.gz
tar xvf php-5.2.6.tar
cd php-5.2.6
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-php-5"&gt;
&lt;h2&gt;5. Configure PHP 5&lt;/h2&gt;
&lt;p&gt;The AIX toolbox packages have been compiled with a default prefix of /opt/freeware, and that is where all the files from the packages are installed. As we compile php from scratch, it is good practice to configure the php package to go under /usr/local (see the &amp;quot;prefix&amp;quot; below). The &amp;quot;with-config-file-path&amp;quot; sets the the place where PHP searches for its' configuration file.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
export PATH=/opt/freeware/bin:$PATH

./configure \
  --prefix=/usr/local \
  --with-config-file-path=/usr/IBMIHS/conf/php.ini \
  --enable-shared \
  --disable-static \
  --enable-maintainer-zts \
  --enable-calendar \
  --enable-bcmath \
  --enable-sockets \
  --enable-zip \
  --with-gd \
  --with-zlib \
  --with-libxml-dir=/opt/freeware \
  --with-zlib-dir=/opt/freeware \
  --with-bz2 \
  --with-gettext=/opt/freeware \
  --with-jpeg-dir=/opt/freeware \
  --with-png-dir=/opt/freeware \
  --with-freetype-dir=/opt/freeware
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="compile"&gt;
&lt;h2&gt;6. Compile&lt;/h2&gt;
&lt;p&gt;Compile:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
make
&lt;/pre&gt;
&lt;p&gt;You may run into the following errors while compiling:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cc1: out of memory allocating XXX bytes after a total YYY of bytes&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is a ulimit issue. Rise the soft limits to overcome it:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ulimit -S -s 3276800    # stack
ulimit -S -m 13107200  # memory
ulimit -S -d 13107200  # data area
&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;execvp: /bin/sh: The parameter or environment lists are too long.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The parameter list to a command is too long. This limit can be raised. Check out the size with this command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
lsattr -El sys0 -a ncargs
&lt;/pre&gt;
&lt;p&gt;Rise it with this command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
chdev -l sys0 -a ncargs=60
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="test"&gt;
&lt;h2&gt;7. Test&lt;/h2&gt;
&lt;pre class="code literal-block"&gt;
make test
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="install"&gt;
&lt;h2&gt;8. Install&lt;/h2&gt;
&lt;pre class="code literal-block"&gt;
make install
cp php.ini-recommended /usr/IBMIHS/conf/php.ini
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-ihs"&gt;
&lt;h2&gt;9. Configure IHS&lt;/h2&gt;
&lt;p&gt;I added the following lines to httpd.conf:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ScriptAlias /php5-cgi /usr/local/bin/php-cgi
Action php-cgi /php5-cgi
AddHandler php-cgi .php
&lt;/pre&gt;
&lt;p&gt;Also, to make index.php work, modify the DirectoryIndex directive:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
DirectoryIndex index.html index.html.var index.php
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="test-that-everything-works"&gt;
&lt;h2&gt;10. Test that everything works&lt;/h2&gt;
&lt;p&gt;Test the configuration with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/usr/IBMIHS/bin/apachectl -t
&lt;/pre&gt;
&lt;p&gt;And restart IHS to make the new configuration effective:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/usr/IBMIHS/bin/apachectl restart
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="links"&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Using the GNU C/C++ compiler on AIX&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://www.ibm.com/developerworks/aix/library/au-gnu.html"&gt;http://www.ibm.com/developerworks/aix/library/au-gnu.html&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;- The authors explain why you should use GCC compiler, which compiler options are specific to pSeries, what you need to know about shared libraries, and common gotchas and solutions.&lt;/div&gt;
&lt;/div&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;IBM AIX Toolbox download information&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/download.html"&gt;http://www-03.ibm.com/systems/power/software/aix/linux/toolbox/download.html&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Hosting PHP Applications on the IBM HTTP Server&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://www.ibm.com/developerworks/opensource/library/os-phphttp/"&gt;http://www.ibm.com/developerworks/opensource/library/os-phphttp/&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;Raising the command line and environment limit:&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://www.ibm.com/developerworks/forums/thread.jspa?threadID=170563"&gt;http://www.ibm.com/developerworks/forums/thread.jspa?threadID=170563&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="AIX"></category><category term="Apache"></category><category term="PHP"></category><category term="UNIX"></category></entry><entry><title>SSH tunneling your way through multiple gateways</title><link href="https://mikko.kortelainen.io/blog/ssh-tunneling-your-way-through-multiple-gateways/" rel="alternate"></link><published>2008-10-19T17:56:00+03:00</published><updated>2008-10-19T17:56:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-10-19:/blog/ssh-tunneling-your-way-through-multiple-gateways/</id><summary type="html">&lt;p&gt;Ths SSH protocol supports tunneling arbitrary ports from your local host to a
remote network that is only reachable through a remote gateway machine. The
typical situation is that you have a, say, web server in a network which is only
accessible from inside the network. If you have an …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ths SSH protocol supports tunneling arbitrary ports from your local host to a
remote network that is only reachable through a remote gateway machine. The
typical situation is that you have a, say, web server in a network which is only
accessible from inside the network. If you have an ssh gateway machine within
the network, you can get to the web server using tunneling.&lt;/p&gt;
&lt;div class="section" id="a-simple-tunnel"&gt;
&lt;h2&gt;A Simple Tunnel&lt;/h2&gt;
&lt;p&gt;This is what a typical one-gateway tunneling looks like:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/sshgw1.png"&gt;&lt;img alt="image0" class="alignnone size-full wp-image-120" src="https://mikko.kortelainen.io/blog/files/sshgw1.png" style="width: 463px; height: 123px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here's how to set it up:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;laptop:~ $ ssh -L 8080:webserver:80 gw
mkortela&amp;#64;gw:~ $
&lt;/pre&gt;
&lt;p&gt;Now I can connect to my laptop's &lt;em&gt;localhost:8080&lt;/em&gt; and access the webserver's
content. I chose port 8080 because port 80 is a restricted port (you need to be
root to listen to ports under 1024). Also, make sure to choose a port which is
not in use.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="multiple-gateways"&gt;
&lt;h2&gt;Multiple Gateways&lt;/h2&gt;
&lt;p&gt;If there are multiple gateway hosts between local host and the webserver, the
solution becomes a little bit more tricky. I have to make sure that the tunnel
goes all the way from my laptop to the last gateway, which then forwards the
connection to the target web server.&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/sshgw2.png"&gt;&lt;img alt="image1" class="alignnone size-full wp-image-121" src="https://mikko.kortelainen.io/blog/files/sshgw2.png" style="width: 660px; height: 123px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;laptop:~ $ ssh -L 1234:localhost:1234 gw1
mkortela&amp;#64;gw1:~ $ ssh -L 1234:webserver:80 gw2
mkortela&amp;#64;gw2:~ $
&lt;/pre&gt;
&lt;p&gt;Now I am be able to connect to my laptop's &lt;em&gt;localhost:1234&lt;/em&gt;, which is tunneled
over two ssh tunnels to webserver:80.&lt;/p&gt;
&lt;p&gt;A shorter form:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;laptop:~ $ ssh -L 1234:localhost:1234 gw1 &amp;quot;ssh -L 1234:server:1234 gw2&amp;quot;
&lt;/pre&gt;
&lt;p&gt;You can add as many hops as you like.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;laptop:~ $ ssh -L 1234:localhost:1234 gw1
mkortela&amp;#64;gw1:~ $ ssh -L 1234:localhost:1234 gw2
mkortela&amp;#64;gw2:~ $ ssh -L 1234:localhost:1234 gw3
mkortela&amp;#64;gw3:~ $ ssh -L 1234:webserver:80 gw4
mkortela&amp;#64;gw4:~ $
&lt;/pre&gt;
&lt;p&gt;Just make sure the port you choose is not in use on any machine. You can use a
different port for each hop if you like.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="links"&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.openbsd.org/cgi-bin/man.cgi?query=ssh&amp;amp;sektion=1"&gt;http://www.openbsd.org/cgi-bin/man.cgi?query=ssh&amp;amp;sektion=1&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="OpenSSH"></category></entry><entry><title>Dynamic IPv6 routing with Cisco IOS and Quagga on OpenWRT</title><link href="https://mikko.kortelainen.io/blog/dynamic-ipv6-routing-with-cisco-ios-and-quagga-on-openwrt/" rel="alternate"></link><published>2008-10-19T17:46:00+03:00</published><updated>2008-10-19T17:46:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-10-19:/blog/dynamic-ipv6-routing-with-cisco-ios-and-quagga-on-openwrt/</id><summary type="html">&lt;p&gt;Here's how to make dynamic IPv6 routing work between a Cisco IOS router and an OpenWRT Linux &lt;a class="reference external" href="http://quagga.net/"&gt;Quagga&lt;/a&gt; router. I couldn't find a similar howto anywhere, so I decided to write my own.&lt;/p&gt;
&lt;p&gt;I am using OpenWRT Kamikaze 7.09 (kernel 2.4) on an ASUS WL-500gP wireless router. Any …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's how to make dynamic IPv6 routing work between a Cisco IOS router and an OpenWRT Linux &lt;a class="reference external" href="http://quagga.net/"&gt;Quagga&lt;/a&gt; router. I couldn't find a similar howto anywhere, so I decided to write my own.&lt;/p&gt;
&lt;p&gt;I am using OpenWRT Kamikaze 7.09 (kernel 2.4) on an ASUS WL-500gP wireless router. Any IPv6 enabled Cisco router should do.&lt;/p&gt;
&lt;p&gt;I assume you have already installed the IPV6 kernel modules and userland tools, and set up static addresses for your interfaces (if you haven't check out the &lt;a class="reference external" href="http://wiki.openwrt.org/IPv6_howto"&gt;OpenWRT IPv6 Howto&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;I am using &lt;a class="reference external" href="http://www.sixxs.net/"&gt;SixXS&lt;/a&gt; for tunneling an IPv6 /48 prefix over IPv4. Here's a diagram of my setup:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external image-reference" href="https://mikko.kortelainen.io/blog/files/dynamicrouting.png"&gt;&lt;img alt="image0" class="alignnone size-full wp-image-119" src="https://mikko.kortelainen.io/blog/files/dynamicrouting.png" style="width: 348px; height: 611px;" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="section" id="install-quagga"&gt;
&lt;h2&gt;Install Quagga&lt;/h2&gt;
&lt;p&gt;To install Quagga, add the Kamikaze 7.06 repository (the 7.09 repository does not have Quagga yet).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# echo &amp;quot;src oldrelease http://downloads.openwrt.org/kamikaze/7.06/brcm47xx-2.6/packages&amp;quot; &amp;gt;&amp;gt;/etc/ipkg.conf
root&amp;#64;OpenWrt:~# ipkg update
root&amp;#64;OpenWrt:~# ipkg install quagga
root&amp;#64;OpenWrt:~# ipkg install quagga-libzebra
root&amp;#64;OpenWrt:~# ipkg install quagga-ripngd
&lt;/pre&gt;
&lt;p&gt;If you want to use OSPFv3 for IPv6, install also the ospf6d package:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# ipkg install quagga-ospf6d
&lt;/pre&gt;
&lt;p&gt;In this howto, we will use the ripngd daemon because it is easier to set up and good enough for our small network.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-zebra"&gt;
&lt;h2&gt;Configure Zebra&lt;/h2&gt;
&lt;p&gt;To create an initial configuration file for the Zebra daemon, create a /etc/quagga/zebra.conf:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
!
! Zebra configuration file
!
hostname wl1
password zebra
enable password zebra
!
log stdout
!
!
&lt;/pre&gt;
&lt;p&gt;You should, of course, customize your passwords (and hostname). Then start Quagga daemons:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# /etc/init.d/quagga start
quagga.init: Starting zebra ... done.
quagga.init: Starting watchquagga ... done.
&lt;/pre&gt;
&lt;p&gt;Two new processes should be running, the Zebra daemon and the &amp;quot;watchguagga&amp;quot; daemon:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
5083 quagga      852 S   /usr/sbin/zebra -d
5088 root        424 S   /usr/sbin/watchquagga -d -z -T 60 -R /usr/sbin/quagga.init watchrestart zebra
&lt;/pre&gt;
&lt;p&gt;You can now telnet to the default port:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# telnet localhost 2601

Entering character mode
Escape character is '^]'.

Hello, this is Quagga (version 0.98.6).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

User Access Verification

Password:
wl1&amp;gt; ?
  echo      Echo a message back to the vty
  enable    Turn on privileged mode command
  exit      Exit current mode and down to previous mode
  help      Description of the interactive help system
  list      Print command list
  quit      Exit current mode and down to previous mode
  show      Show running system information
  terminal  Set terminal line parameters
  who       Display who is on vty
wl1&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Very Ciscoish, eh? Although the command set is far from &amp;quot;complete&amp;quot;, many commands work like they do on Cisco IOS:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
wl1&amp;gt; show ip forwarding
IP forwarding is on
wl1&amp;gt; show ipv6 forwarding
ipv6 forwarding is off
wl1&amp;gt; enable
Password:
wl1# conf t
wl1(config)# ipv6 forwarding
wl1# write mem
Configuration saved to /etc/quagga//zebra.conf
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-ripngd"&gt;
&lt;h2&gt;Configure ripngd&lt;/h2&gt;
&lt;p&gt;The Zebra daemon does not handle any dynamic routing, it just works as a routing information redistributor. It will forward routing information between different dynamic routing daemons (ospf, rip, bgp) and the kernel routing table. Whenever the ripng daemon detects a change in the network's routing configuration, it will hand down the change to Zebra, which in turn will make a modification to the kernel routing table (which is the actual, effective routing table). If you have another routing daemon process running, Zebra will also notify that daemon about the change.&lt;/p&gt;
&lt;p&gt;To configure ripngd, create an initial config:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# echo hostname wl1 &amp;gt; /etc/quagga/ripngd.conf
root&amp;#64;OpenWrt:~# echo router ripng &amp;gt;&amp;gt; /etc/quagga/ripngd.conf
root&amp;#64;OpenWrt:~# echo password zebra &amp;gt;&amp;gt; /etc/quagga/ripngd.conf
root&amp;#64;OpenWrt:~# echo enable password zebra &amp;gt;&amp;gt; /etc/quagga/ripngd.conf
&lt;/pre&gt;
&lt;p&gt;Then restart quagga:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# /etc/init.d/quagga restart
quagga.init: Stopping watchquagga ... killed 11576 ... done.
quagga.init: Stopping zebra ... killed 11571 ... done.
quagga.init: Starting zebra ... done.
quagga.init: Starting ripngd ... done.
quagga.init: Starting watchquagga ... done.
&lt;/pre&gt;
&lt;p&gt;Configure dynamic routing with RIP:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# telnet localhost 2603

Entering character mode
Escape character is '^]'.

Hello, this is Quagga (version 0.98.6).
Copyright 1996-2005 Kunihiro Ishiguro, et al.

User Access Verification

Password:
wl1&amp;gt; enable
Password:
wl1# conf t
wl1(config)# router ripng
wl1(config-router)# network br-lan
wl1(config-router)# network eth0.1
wl1(config-router)# end
wl1# wr mem
Configuration saved to /etc/quagga//ripngd.conf
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="cisco-ios-configuration"&gt;
&lt;h2&gt;Cisco IOS Configuration&lt;/h2&gt;
&lt;p&gt;Next we will have to configure the other participant of the dynamic routing process. I am using a Cisco 877W with Advanced IP Services (you don't get IPv6 support below that level).&lt;/p&gt;
&lt;p&gt;Cisco IOS Configuration:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cisco#conf t
cisco(config)#ipv6 router rip ripng
cisco(config-rtr)#redistribute connected
cisco(config-rtr)#redistribute static
cisco(config)#interface vlan 1
cisco(config-if)#ipv6 rip ripng enable
&lt;/pre&gt;
&lt;p&gt;That's it! After a while you should see the routes propagated between the two routers:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;OpenWrt:~# ip -f inet6 route
2001:db8:100:100::/64 via fe80::21c:eff:fed9:32ef dev eth0.1  proto zebra  metric 2  mtu 1500 advmss 1440
2001:db8:0:1::/64 dev eth0.1  proto kernel  metric 256  expires 2584987sec mtu 1500 advmss 1440
2001:db8:0:3::/64 dev br-lan  metric 256  mtu 1500 advmss 1440
2000::/3 via fe80::21c:eff:fed9:32ef dev eth0.1  proto zebra  metric 2  mtu 1500 advmss 1440
fe80::/64 dev eth0  metric 256  mtu 1500 advmss 1440
fe80::/64 dev eth0.0  metric 256  mtu 1500 advmss 1440
fe80::/64 dev br-lan  metric 256  mtu 1500 advmss 1440
fe80::/64 dev eth0.1  metric 256  mtu 1500 advmss 1440
fe80::/64 dev wl0  metric 256  mtu 1500 advmss 1440
ff00::/8 dev eth0  metric 256  mtu 1500 advmss 1440
ff00::/8 dev eth0.0  metric 256  mtu 1500 advmss 1440
ff00::/8 dev br-lan  metric 256  mtu 1500 advmss 1440
ff00::/8 dev eth0.1  metric 256  mtu 1500 advmss 1440
ff00::/8 dev wl0  metric 256  mtu 1500 advmss 1440
unreachable default dev lo  proto none  metric -1  error -128
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
cisco#show ipv6 route
IPv6 Routing Table - 8 entries
Codes: C - Connected, L - Local, S - Static, R - RIP, B - BGP
       U - Per-user Static route
       I1 - ISIS L1, I2 - ISIS L2, IA - ISIS interarea, IS - ISIS summary
       O - OSPF intra, OI - OSPF inter, OE1 - OSPF ext 1, OE2 - OSPF ext 2
       ON1 - OSPF NSSA ext 1, ON2 - OSPF NSSA ext 2
       D - EIGRP, EX - EIGRP external
S   2000::/3 [1/0]
     via 2001:14B8:100:1DB::1
C   2001:db8:100:100::/64 [0/0]
     via ::, Tunnel0
L   2001:db8:100:100::2/128 [0/0]
     via ::, Tunnel0
C   2001:db8:0:1::/64 [0/0]
     via ::, Vlan1
L   2001:db8:0:1::1/128 [0/0]
     via ::, Vlan1
R   2001:db8:0:2::/64 [120/2]
     via FE80::217:31FF:FED6:983E, Vlan1
L   FE80::/10 [0/0]
     via ::, Null0
L   FF00::/8 [0/0]
     via ::, Null0
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="links"&gt;
&lt;h2&gt;Links&lt;/h2&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://wiki.openwrt.org/IPv6_howto"&gt;http://wiki.openwrt.org/IPv6_howto&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://quagga.net/docs.php"&gt;http://quagga.net/docs.php&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://www.sixxs.net/"&gt;http://www.sixxs.net/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://en.wikipedia.org/wiki/IPv6"&gt;http://en.wikipedia.org/wiki/IPv6&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Cisco"></category><category term="IPv6"></category><category term="Linux"></category><category term="Networking"></category><category term="OpenWRT"></category></entry><entry><title>Sendmail relay configuration on AIX</title><link href="https://mikko.kortelainen.io/blog/sendmail-relay-configuration-on-aix/" rel="alternate"></link><published>2008-09-18T11:32:00+03:00</published><updated>2008-09-18T11:32:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-09-18:/blog/sendmail-relay-configuration-on-aix/</id><summary type="html">&lt;p&gt;This document describes how to set up a Sendmail e-mail gateway or relay which
will be able to process incoming mail and route it to different mail servers
based on domain information. The routing table is based on the Sendmail
&lt;em&gt;mailertable&lt;/em&gt; feature instead of the usual MX record based routing …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This document describes how to set up a Sendmail e-mail gateway or relay which
will be able to process incoming mail and route it to different mail servers
based on domain information. The routing table is based on the Sendmail
&lt;em&gt;mailertable&lt;/em&gt; feature instead of the usual MX record based routing. This will
come handy when there is a need to route mail internally in a different way than
externally.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="aix-configuration"&gt;
&lt;h2&gt;AIX configuration&lt;/h2&gt;
&lt;p&gt;Make sure &amp;quot;bos.net.tcp.adt&amp;quot; is installed.&lt;/p&gt;
&lt;p&gt;The file &lt;em&gt;/usr/samples/tcpip/sendmail/cf/aixsample.mc&lt;/em&gt; describes a minimal
sample configuration. That can be used as the basis of your configuration.
Please note however that there are some dangerous default settings in that file
which must be changed before deployment.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="sendmail-configuration-the-sendmail-mc"&gt;
&lt;h2&gt;Sendmail configuration: the &lt;em&gt;sendmail.mc&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;I made my &lt;em&gt;/etc/mail/sendmail.mc&lt;/em&gt; look like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
divert(0)dnl
OSTYPE(aixsample)dnl
FEATURE(`mailertable',`dbm /etc/mail/mailertable')dnl
FEATURE(virtusertable)dnl
FEATURE(domaintable)dnl
FEATURE(no_default_msa)
FEATURE(relay_hosts_only)dnl
FEATURE(access_db)
FEATURE(`greet_pause',5000)dnl
DOMAIN(generic)dnl
define(`confSMTP_LOGIN_MSG', `$j Sendmail $b')
define(`confPRIVACY_FLAGS',`authwarnings,novrfy,noexpn,noverb')dnl
define(`confBAD_RCPT_THROTTLE', `1')dnl
define(`confCONNECTION_RATE_THROTTLE', `100')dnl
MAILER(local)dnl
MAILER(smtp)dnl
MAILER(uucp)
DAEMON_OPTIONS(`Port=smtp, Name=MTA')dnl
&lt;/pre&gt;
&lt;p&gt;To process the .mc file into a proper Sendmail configuration file,
&lt;em&gt;sendmail.cf&lt;/em&gt;, use the following commands:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cd /usr/samples/tcpip/sendmail/m4/
m4 cf.m4 /etc/mail/sendmail.mc &amp;gt; /etc/mail/sendmail.cf
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="security"&gt;
&lt;h2&gt;Security&lt;/h2&gt;
&lt;p&gt;I removed three lines and added one to the sample configuration file for
security before deploying it.&lt;/p&gt;
&lt;p&gt;I removed the lines:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
FEATURE(accept_unresolvable_domains)dnl
FEATURE(accept_unqualified_senders)dnl
FEATURE(promiscuous_relay)dnl
&lt;/pre&gt;
&lt;div class="section" id="promiscuous-relay"&gt;
&lt;h3&gt;&lt;em&gt;promiscuous_relay&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;This is important!&lt;/strong&gt; Leaving the &lt;em&gt;promiscuous_relay&lt;/em&gt; feature on will make your
&lt;em&gt;server an open relay and thus a good host for spammers to do what they do. It
*being a default setting is quite unbelievable. **So remember to remove it.*&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There is usually no need to keep the other two options, accepting unresolvable
domains or unqualified senders. Those will just close some holes form spammers.&lt;/p&gt;
&lt;p&gt;The lines I added to the sample configuration are:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
FEATURE(relay_hosts_only)dnl
FEATURE(access_db)
FEATURE(`greet_pause',5000)dnl
define(`confPRIVACY_FLAGS',`authwarnings,novrfy,noexpn,noverb')dnl
define(`confBAD_RCPT_THROTTLE', `1')dnl
define(`confCONNECTION_RATE_THROTTLE', `100')dnl
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="greet-pause"&gt;
&lt;h3&gt;&lt;em&gt;greet_pause&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;greet_pause&lt;/em&gt; feature makes sendmail wait for a specified amount of time at
the beginning of an incoming connection, before greeting the connecting party. A
value of 5000 means 5 seconds. Proper mail clients will wait for the greeting,
while many spambots start flooding immediately. They will be discarded by this
rule.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="authwarnings"&gt;
&lt;h3&gt;&lt;em&gt;authwarnings&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;authwarnings&lt;/em&gt; privacy flag tells sendmail to insert
X-Authentication-Warnings: headers into the mail whenever it suspects that the
message is not authentic.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="novrfy"&gt;
&lt;h3&gt;&lt;em&gt;novrfy&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;novrfy&lt;/em&gt; privacy flag will deny email address verification queries (the VRFY
allows anyone to check if a user exists in your mail server - this will prevent
it).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="noexpn"&gt;
&lt;h3&gt;&lt;em&gt;noexpn&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;noexpn&lt;/em&gt; privacy flag will deny mailing list queries (the EXPN allows anyone
to check who belongs to your mailing lists - this will precent it).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="noverb"&gt;
&lt;h3&gt;&lt;em&gt;noverb&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;noverb&lt;/em&gt; privacy flag will deny requests for verbose mode, which might
reveal information about your installation to an outsider.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="bad-rcpt-throttle"&gt;
&lt;h3&gt;&lt;em&gt;BAD_RCPT_THROTTLE&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;BAD_RCPT_THROTTLE&lt;/em&gt; setting will add an additional annoyance for spammers.
If a specified number of recipients in a single SMTP transaction have been
rejected, sendmail will sleep for one second after each subsequent RCPT command
in that transaction. That will make it impractical to try and guess usernames.
Legitimate mail will get delivered, though.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="connection-rate-throttle"&gt;
&lt;h3&gt;&lt;em&gt;CONNECTION_RATE_THROTTLE&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;The &lt;em&gt;CONNECTION_RATE_THROTTLE&lt;/em&gt; Sets the maximum number of connections permitted
per second per daemon. After this many connections are accepted, further
connections will be delayed. It will protect agains denial-of-service attacks
and spammers opening hundreds of connections to your server.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="allow-incoming-mail-relay"&gt;
&lt;h2&gt;Allow incoming mail relay&lt;/h2&gt;
&lt;p&gt;Add the domains you wish to serve to /etc/mail/local-host-names:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
targetdomain1.com
targetdomain2.com
targetdomain3.com
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="domain-based-routing-the-mailertable"&gt;
&lt;h2&gt;Domain-based routing: the &lt;em&gt;mailertable&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;This is a feature that allows you to route mail to certain domains via given
mail gateways.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;/etc/mail/mailertable&lt;/em&gt; could look like this (please edit before deploying):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
targetdomain1.com          smtp:targethost1.example.com
targetdomain2.com          smtp:targethost2.test.net
targetdomain3.com          smtp:[192.168.0.1]
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="allow-incoming-relay-the-access"&gt;
&lt;h2&gt;Allow incoming relay: the &lt;em&gt;access&lt;/em&gt;&lt;/h2&gt;
&lt;p&gt;The mail domains your server is allowed to relay from outside (the Internet)
must be listed in the &lt;em&gt;/etc/mail/access&lt;/em&gt;&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
To:targetdomain1.com  RELAY
To:targetdomain2.com  RELAY
To:targetdomain3.com  RELAY
&lt;/pre&gt;
&lt;p&gt;This feature needs the &lt;em&gt;access_db&lt;/em&gt; feature to be enabled in &lt;em&gt;sendmail.mc&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Don't put these domains in the &lt;em&gt;/etc/mail/local-hosts&lt;/em&gt; file (you should put
there only the mail domains your host will receive itself).&lt;/p&gt;
&lt;div class="section" id="allow-outgoing-relay-optional"&gt;
&lt;h3&gt;Allow outgoing relay (optional)&lt;/h3&gt;
&lt;p&gt;This part is optional but useful. If you want hosts in your internal network to
be able to use the server as an outgoing relay, add the hosts to the file
&lt;em&gt;/etc/mail/access&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
192.168.0.    RELAY
192.168.1.1   RELAY
192.168.1.2   RELAY
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="other-configuration-files"&gt;
&lt;h2&gt;Other configuration files&lt;/h2&gt;
&lt;p&gt;Also, create some files sendmail wants to see in &lt;em&gt;/etc/mail&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
touch /etc/mail/domaintable
touch /etc/mail/virtusertable
touch /etc/mail/local-host-names
&lt;/pre&gt;
&lt;p&gt;Make the configuration files readable by everybody:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
chmod 644 /etc/mail/*
&lt;/pre&gt;
&lt;p&gt;Make sure your &lt;em&gt;/etc/syslog.conf&lt;/em&gt; includes a line like:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mail.debug                      /var/log/maillog
&lt;/pre&gt;
&lt;p&gt;That will put mail related entries into their own log file.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="updating-configuration-with-make"&gt;
&lt;h2&gt;Updating configuration with make&lt;/h2&gt;
&lt;p&gt;To keep configuration files and Sendmail database files up to date, I usually
create a Makefile which includes the rules to compile all changed configuration
files. This is what I used here. The contents of &lt;em&gt;/etc/mail/Makefile&lt;/em&gt; look like
this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
all: access.db access.dir access.pag \
     aliases.db aliases.dir aliases.pag \
     domaintable.db domaintable.dir domaintable.pag \
     mailertable.db mailertable.dir mailertable.pag \
     virtusertable.db virtusertable.dir virtusertable.pag \
     sendmail.cf

access.db: access
        makemap hash /etc/mail/access &amp;lt;/etc/mail/access

access.dir access.pag: access
        makemap dbm /etc/mail/access &amp;lt;/etc/mail/access

aliases.db: aliases
        makemap hash /etc/mail/aliases &amp;lt;/etc/mail/aliases

aliases.dir aliases.pag: aliases
        makemap dbm /etc/mail/aliases &amp;lt;/etc/mail/aliases

domaintable.db: domaintable
        makemap hash /etc/mail/domaintable &amp;lt;/etc/mail/domaintable

domaintable.dir domaintable.pag: domaintable
        makemap dbm /etc/mail/domaintable &amp;lt;/etc/mail/domaintable

mailertable.db: mailertable
        makemap hash /etc/mail/mailertable &amp;lt;/etc/mail/mailertable

mailertable.dir mailertable.pag: mailertable
        makemap dbm /etc/mail/mailertable &amp;lt;/etc/mail/mailertable

virtusertable.db: virtusertable
        makemap hash /etc/mail/virtusertable &amp;lt;/etc/mail/virtusertable

virtusertable.dir virtusertable.pag: virtusertable
        makemap hash /etc/mail/virtusertable &amp;lt;/etc/mail/virtusertable

sendmail.cf: sendmail.mc
        cd /usr/samples/tcpip/sendmail/m4; \
        m4 cf.m4 /etc/mail/sendmail.mc &amp;gt; /etc/mail/sendmail.cf
&lt;/pre&gt;
&lt;p&gt;That way, after you make changes to configuration files, just go to /etc/mail
and run &lt;em&gt;make&lt;/em&gt;. That will update all configuration files as needed. Give the
sendmail process a &lt;em&gt;kill -HUP&lt;/em&gt; after that to make it read its configuration
again.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cd /etc/mail
make
kill -HUP
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="running-sendmail"&gt;
&lt;h2&gt;Running Sendmail&lt;/h2&gt;
&lt;p&gt;Start command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
startsrc -s sendmail -a &amp;quot;-bd -q30m&amp;quot;
&lt;/pre&gt;
&lt;p&gt;Stop command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
stopsrc -s sendmail
&lt;/pre&gt;
&lt;p&gt;Update configuration (see section above):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
cd /etc/mail
make
kill -HUP
&lt;/pre&gt;
&lt;p&gt;See the queue:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sendmail -bp
&lt;/pre&gt;
&lt;p&gt;Watch your mail log:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
tail -f /var/log/maillog
&lt;/pre&gt;
&lt;p&gt;Watch while Sendmail processes the mail queue:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sendmail -q -v
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="routing-your-mail-the-dns-records"&gt;
&lt;h2&gt;Routing your mail: the DNS records&lt;/h2&gt;
&lt;p&gt;When your new relay server is up and running, and verified to work correctly, it
is time to update the DNS records of the domains to route mail through your new
server(s).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
targetdomain1.com. IN MX 10 mail1.koo.fi.
targetdomain2.com. IN MX 10 mail2.koo.fi.
&lt;/pre&gt;
&lt;p&gt;The second part is needed only if you configured two servers. The number &amp;quot;10&amp;quot;
there is priority. By giving both servers the same priority, incoming mail will
be split somewhat equally between them.&lt;/p&gt;
&lt;p&gt;Also make sure your own domain has A records for the mail server:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mail1.koo.fi. IN A 192.168.1.1
mail2.koo.fi. IN A 192.168.1.2
&lt;/pre&gt;
&lt;p&gt;And third, it is also crucial to add your servers to your IP network's reverse
lookup DNS zone. In this example case it would be the &lt;em&gt;1.168.192.in-addr.arpa&lt;/em&gt;
domain:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
1.1.168.192.in-addr.arpa. IN PTR mail1.koo.fi.
2.1.168.192.in-addr.arpa. In PTR mail2.koo.fi.
&lt;/pre&gt;
&lt;p&gt;A reverse mapping is needed, because a lot of Internet's mail servers are
configured to check for its existence. This, once again, to make life harder for
spammers.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="AIX"></category><category term="Sendmail"></category><category term="UNIX"></category></entry><entry><title>NIC bonding with Ubuntu</title><link href="https://mikko.kortelainen.io/blog/nic-bonding-with-ubuntu/" rel="alternate"></link><published>2008-08-02T21:00:00+03:00</published><updated>2008-08-02T21:00:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-08-02:/blog/nic-bonding-with-ubuntu/</id><summary type="html">&lt;p&gt;Network interfaces can be bonded to provide fault-tolerant operation. Here's how
to do it in Ubuntu. I will assume the interfaces to be bonded are eth0 and eth1.&lt;/p&gt;
&lt;p&gt;First, install the ifenslave package. The ifenslave tool will be used to
actually bond the interfaces.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
apt-get install ifenslave
&lt;/pre&gt;
&lt;p&gt;Create file &lt;em&gt;/etc …&lt;/em&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Network interfaces can be bonded to provide fault-tolerant operation. Here's how
to do it in Ubuntu. I will assume the interfaces to be bonded are eth0 and eth1.&lt;/p&gt;
&lt;p&gt;First, install the ifenslave package. The ifenslave tool will be used to
actually bond the interfaces.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
apt-get install ifenslave
&lt;/pre&gt;
&lt;p&gt;Create file &lt;em&gt;/etc/modprobe.d/bonding&lt;/em&gt; with the following contents:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
alias bond0 bonding
options bonding mode=0 miimon=100
&lt;/pre&gt;
&lt;p&gt;Load the bonding module:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
modprobe bonding
&lt;/pre&gt;
&lt;p&gt;Add a bonded interface into /etc/network/interfaces:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
auto bond0
iface bond0 inet static
  address 192.168.0.1
  gateway 192.168.0.254
  netmask 255.255.255.0
  pre-up modprobe bonding
  up ifenslave bond0 eth0 eth1
  pre-down ifenslave bond0 -d eth0 eth1
  post-down rmmod bonding
&lt;/pre&gt;
&lt;p&gt;Restart networking:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/etc/init.d/networking restart
&lt;/pre&gt;
&lt;p&gt;That's it! The bonded interface should come up automatically after a reboot as well.&lt;/p&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="Networking"></category><category term="Ubuntu"></category></entry><entry><title>Windows Server Time with NTP</title><link href="https://mikko.kortelainen.io/blog/windows-server-time-with-ntp/" rel="alternate"></link><published>2008-08-02T13:34:00+03:00</published><updated>2008-08-02T13:34:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-08-02:/blog/windows-server-time-with-ntp/</id><summary type="html">&lt;p&gt;Here's how to configure a Windows domain controller to act as an NTP client and
server for your network. You may then sync all your hosts, Windows or other, to
that server. To achieve this, configure one (or more) of your domain controllers
to retrieve time from the atomic clocks …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's how to configure a Windows domain controller to act as an NTP client and
server for your network. You may then sync all your hosts, Windows or other, to
that server. To achieve this, configure one (or more) of your domain controllers
to retrieve time from the atomic clocks of the Internet. Rest of you servers
should follow suit and sync their time to this domain controller after a little
while.&lt;/p&gt;
&lt;p&gt;You must allow the NTP protocol to pass through your firewall. This can be
achieved by allowing tcp/123 and udp/123 traffic.&lt;/p&gt;
&lt;p&gt;To retrieve time from the Internet and serve it to computers on your network,
edit or add the following registry keys:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Config]
&amp;quot;AnnounceFlags&amp;quot;=dword:00000005

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\Parameters]
&amp;quot;NtpServer&amp;quot;=&amp;quot;0.europe.pool.ntp.org,0x1 1.europe.pool.ntp.org,0x1 2.europe.pool.ntp.org,0x1&amp;quot;
&amp;quot;Type&amp;quot;=&amp;quot;NTP&amp;quot;

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpClient]
&amp;quot;SpecialPollInterval&amp;quot;=dword:00000e10

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\W32Time\TimeProviders\NtpServer]
&amp;quot;Enabled&amp;quot;=dword:00000001
&lt;/pre&gt;
&lt;p&gt;That configuration will effectively make your server both an NTP client and an
NTP server. SpecialPollInterval is the polling interval in seconds. 0xe10 = 3600
seconds. The NtpServer string is a space-separated list of time providers, each
appended with the string &amp;quot;,0x1&amp;quot;. I use ntp.org European time providers.&lt;/p&gt;
&lt;p&gt;Restart the W32Time service to make the configuration current:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
net stop w32time
net start w32time
&lt;/pre&gt;
&lt;p&gt;To force resynchronization of time:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
w32tm /resync
&lt;/pre&gt;
&lt;p&gt;To monitor the time of your domain controllers:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
w32tm /monitor
&lt;/pre&gt;
&lt;p&gt;To force resynchronization of time on some other server:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
w32tm /resync /computer:REMOTESERVER
&lt;/pre&gt;
&lt;p&gt;You can now configure your non-windows boxes to sync time to the server using
NTP. Windows machines which are AD domain members should sync automatically
without further configuration.&lt;/p&gt;
&lt;p&gt;Links:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://support.microsoft.com/kb/816042"&gt;http://support.microsoft.com/kb/816042&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/ws03mngd/26_s3wts.mspx"&gt;http://www.microsoft.com/technet/prodtechnol/windowsserver2003/technologies/security/ws03mngd/26_s3wts.mspx&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Active Directory"></category><category term="NTP"></category><category term="Windows"></category></entry><entry><title>Adding the First Windows 2008 DC into Active Directory</title><link href="https://mikko.kortelainen.io/blog/adding-the-first-windows-2008-dc-into-active-directory/" rel="alternate"></link><published>2008-06-25T14:49:00+03:00</published><updated>2008-06-25T14:49:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-06-25:/blog/adding-the-first-windows-2008-dc-into-active-directory/</id><summary type="html">&lt;p&gt;Make a backup copy of your AD before you go any further.&lt;/p&gt;
&lt;p&gt;Install your new server, and join it to the domain as a member server. Before you can run &lt;em&gt;dcpromo&lt;/em&gt; on the new 2008 server, you must run adprep on your schema master, to prepare the Active Directory schema …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Make a backup copy of your AD before you go any further.&lt;/p&gt;
&lt;p&gt;Install your new server, and join it to the domain as a member server. Before you can run &lt;em&gt;dcpromo&lt;/em&gt; on the new 2008 server, you must run adprep on your schema master, to prepare the Active Directory schema to support Windows 2008 domain controllers. The installation DVD contains a directory called &lt;em&gt;sourcesadprep&lt;/em&gt;. Go there and run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
D:sourcesadprep&amp;gt;adprep /forestprep
D:sourcesadprep&amp;gt;adprep /domainprep
D:sourcesadprep&amp;gt;adprep /rodcprep
&lt;/pre&gt;
&lt;p&gt;After that you may run &lt;em&gt;dcpromo&lt;/em&gt; to promote the server as a domain controller.&lt;/p&gt;
</content><category term="Blog"></category><category term="Active Directory"></category><category term="Windows"></category></entry><entry><title>Fetching information from Active Directory using Python</title><link href="https://mikko.kortelainen.io/blog/fetching-information-from-active-directory-using-python/" rel="alternate"></link><published>2008-06-19T10:17:00+03:00</published><updated>2008-06-19T10:17:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-06-19:/blog/fetching-information-from-active-directory-using-python/</id><summary type="html">&lt;p&gt;Here are two simple scripts written in Python to fetch information about users from Active Directory. The AD schema has been augmented with the Microsoft Services For Unix schema, which will allow to map Unix uids to Windows user accounts.&lt;/p&gt;
&lt;p&gt;All you need to do is to fill in your …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here are two simple scripts written in Python to fetch information about users from Active Directory. The AD schema has been augmented with the Microsoft Services For Unix schema, which will allow to map Unix uids to Windows user accounts.&lt;/p&gt;
&lt;p&gt;All you need to do is to fill in your own domain controller, AD distinguished name (user account) and the password for it in &lt;em&gt;/etc/ad.secret&lt;/em&gt;. You shoud use a less privileged account than &lt;em&gt;Administrator&lt;/em&gt; for security. Also remember to set the permissions for ad.secret so that only privileged users have access.&lt;/p&gt;
&lt;p&gt;This one will fetch the real name of a user when given a Unix uid:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/usr/bin/python

import sys
import ldap

if len(sys.argv) &amp;lt; 2:
  print &amp;quot;usage: getrealname &amp;lt;username&amp;gt;&amp;quot;
  sys.exit()

Server = &amp;quot;dc1.koo.fi&amp;quot;
DN = &amp;quot;cn=Administrator,cn=Users,dc=koo,dc=fi&amp;quot;
Secret = file(&amp;quot;/etc/ad.secret&amp;quot;).readline().strip()
Base = &amp;quot;dc=koo,dc=fi&amp;quot;
Scope = ldap.SCOPE_SUBTREE
Filter = &amp;quot;(&amp;amp;(objectClass=user)(msSFU30Name=&amp;quot;+sys.argv[1]+&amp;quot;))&amp;quot;
Attrs = [&amp;quot;displayName&amp;quot;, &amp;quot;msSFU30Name&amp;quot;]
l = ldap.open(Server)
l.simple_bind(DN, Secret)
r = l.search(Base, Scope, Filter, Attrs)
Type,user = l.result(r,60)
Name,Attrs = user[0]
if hasattr(Attrs, 'has_key') and Attrs.has_key('displayName'):
  displayName = Attrs['displayName'][0]
  print displayName

sys.exit()
&lt;/pre&gt;
&lt;p&gt;And this one will do the same for e-mail:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/usr/bin/python

import sys
import ldap

if len(sys.argv) &amp;lt; 2:
  print &amp;quot;usage: getemail &amp;lt;username&amp;gt;&amp;quot;
  sys.exit()

Server = &amp;quot;dc1.koo.fi&amp;quot;
DN = &amp;quot;cn=Administrator,cn=Users,dc=koo,dc=fi&amp;quot;
Secret = file(&amp;quot;/etc/ad.secret&amp;quot;).readline().strip()
Base = &amp;quot;dc=koo,dc=fi&amp;quot;
Scope = ldap.SCOPE_SUBTREE
Filter = &amp;quot;(&amp;amp;(objectClass=user)(msSFU30Name=&amp;quot;+sys.argv[1]+&amp;quot;))&amp;quot;
Attrs = [&amp;quot;mail&amp;quot;, &amp;quot;msSFU30Name&amp;quot;]
l = ldap.open(Server)
l.simple_bind(DN, Secret)
r = l.search(Base, Scope, Filter, Attrs)
Type,user = l.result(r,60)
Name,Attrs = user[0]
if hasattr(Attrs, 'has_key') and Attrs.has_key('mail'):
  mail = Attrs['mail'][0]
  print mail

sys.exit()
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Active Directory"></category><category term="Python"></category></entry><entry><title>Apache HTTP authentication to Active Directory with Kerberos</title><link href="https://mikko.kortelainen.io/blog/apache-http-authentication-to-active-directory-with-kerberos/" rel="alternate"></link><published>2008-06-18T19:52:00+03:00</published><updated>2008-06-18T19:52:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-06-18:/blog/apache-http-authentication-to-active-directory-with-kerberos/</id><summary type="html">&lt;p&gt;First, create a user account for your Apache in the Active Directory. Let's assume the AD Kerberos realm is KOO.FI, and the user name we have created is &amp;quot;apache&amp;quot;. Also create a computer account, let's call that &amp;quot;apachesrv&amp;quot;.&lt;/p&gt;
&lt;p&gt;Next, create two keytab files on the Windows server. One host …&lt;/p&gt;</summary><content type="html">&lt;p&gt;First, create a user account for your Apache in the Active Directory. Let's assume the AD Kerberos realm is KOO.FI, and the user name we have created is &amp;quot;apache&amp;quot;. Also create a computer account, let's call that &amp;quot;apachesrv&amp;quot;.&lt;/p&gt;
&lt;p&gt;Next, create two keytab files on the Windows server. One host keytab file and one service keytab file (long lines have been split):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
C:&amp;gt;ktpass -princ HOST/www.koo.fi&amp;#64;KOO.FI -mapuser apachesrv&amp;#64;KOO.FI
-crypto DES-CBC-MD5 -DesOnly -pass XXXCHOOSEXAXSECRETXWORDXXX
-ptype KRB5_NT_SRV_HST -out krb5.keytab
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
C:&amp;gt;ktpass -princ HTTP/www.koo.fi&amp;#64;KOO.FI -mapuser apache&amp;#64;KOO.FI
-pass XXXSECRETXXX -out keytab.HTTP
&lt;/pre&gt;
&lt;p&gt;Make sure that the principal name you are using (HTTP/your.server.com) has the actual domain name that is being requested from Apache by the web browser. If they differ, you will end up having error messages saying &amp;quot;failed to verify krb5 credentials: Server not found in Kerberos database&amp;quot; in you Apache error log.&lt;/p&gt;
&lt;p&gt;You should now have binary files called krb5.keytab and keytab.HTTP in your current directory. Copy those files over to your Apache server into /etc.&lt;/p&gt;
&lt;p&gt;Edit /etc/krb5.conf:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[libdefaults]
        default_realm = KOO.FI
        default_keytab_file = /etc/krb5.keytab
        dns_lookup_realm = true
        dns_lookup_kdc = true

[realms]
        KOO.FI = {
                kdc = dc1.koo.fi
                kdc = dc2.koo.fi
                admin_server = dc1.koo.fi
        }
[domain_realm]
        .koo.fi = KOO.FI
        koo.fi = KOO.FI
&lt;/pre&gt;
&lt;p&gt;Test that your authentication works:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;apachesrv:/etc# kinit HOST/www.koo.fi
Password for HOSTt/www.koo.fi&amp;#64;KOO.FI:
&lt;/pre&gt;
&lt;p&gt;Enter the secret string you used earlier to create the machine account. If everything went correctly, you should be able to list the ticket:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;apachesrv:/etc# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: HOST/www.koo.fi&amp;#64;KOO.FI

Valid starting     Expires            Service principal
06/11/08 15:26:55  06/12/08 01:25:16  krbtgt/KOO.FI&amp;#64;KOO.FI
    renew until 06/12/08 15:26:55

Kerberos 4 ticket cache: /tmp/tkt0
klist: You have no tickets cached
&lt;/pre&gt;
&lt;p&gt;Lastly, let's configure Apache. My Apache server happened to be an Ubuntu box with Apache 2.2 installed. The Apache module &lt;em&gt;mod_auth_kerb&lt;/em&gt; will take care of the authentication, so let's install that:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;apachesrv:/etc# aptitude install libapache2-mod-auth-kerb
&lt;/pre&gt;
&lt;p&gt;Add a directory directive in your Apache configuration file:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
&amp;lt;Directory /var/www/www.koo.fi/protected&amp;gt;
  AuthType Kerberos
  KrbMethodNegotiate on
  KrbMethodK5Passwd on
  KrbAuthoritative on
  KrbAuthRealms KOO.FI
  KrbVerifyKDC on
  KrbServiceName HTTP
  Krb5Keytab /etc/keytab.HTTP
  KrbSaveCredentials off
  AuthName &amp;quot;This url is protected. Keep your unauthorized hands off!&amp;quot;
  Require Valid-user
&amp;lt;/Directory&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Reload the changes to Apache, and you're all set!&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;apachesrv:/etc# /etc/init.d/apache2 force-reload
&lt;/pre&gt;
&lt;p&gt;Some links:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://sl.mvps.org/docs/LinuxApacheKerberosAD.htm"&gt;http://sl.mvps.org/docs/LinuxApacheKerberosAD.htm&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://blog.scottlowe.org/2006/08/08/linux-active-directory-and-windows-server-2003-r2-revisited/"&gt;http://blog.scottlowe.org/2006/08/08/linux-active-directory-and-windows-server-2003-r2-revisited/&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://modauthkerb.sourceforge.net/configure.html"&gt;http://modauthkerb.sourceforge.net/configure.html&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Active Directory"></category><category term="Apache"></category><category term="Kerberos"></category><category term="Linux"></category></entry><entry><title>HP Array Configuration and Diagnostic Utilities on Linux</title><link href="https://mikko.kortelainen.io/blog/hp-array-configuration-and-diagnostic-utilities-on-linux/" rel="alternate"></link><published>2008-06-08T14:52:00+03:00</published><updated>2008-06-08T14:52:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-06-08:/blog/hp-array-configuration-and-diagnostic-utilities-on-linux/</id><summary type="html">&lt;p&gt;Getting the HP Array Configuration Utility (ACU) and the Array Diagnostic Utility (ADU) for Linux to work was non-trivial. It does not seem to be supported anymore, but I managed to get it working on CentOS 5 running on an HP ProLiant DL185 G5.&lt;/p&gt;
&lt;p&gt;First, install compatibility packages:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo yum …&lt;/pre&gt;</summary><content type="html">&lt;p&gt;Getting the HP Array Configuration Utility (ACU) and the Array Diagnostic Utility (ADU) for Linux to work was non-trivial. It does not seem to be supported anymore, but I managed to get it working on CentOS 5 running on an HP ProLiant DL185 G5.&lt;/p&gt;
&lt;p&gt;First, install compatibility packages:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo yum install compat-libstdc++-33.i386 compat-libstdc++-33.x86_64 \
                 compat-libstdc++-296.i386
&lt;/pre&gt;
&lt;p&gt;Then, download and install the packages HP provides:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
wget -nd ftp://ftp.hp.com/pub/products/servers/supportsoftware/linux/hpacucli-7.70-12.linux.rpm
wget -nd ftp://ftp.hp.com/pub/products/servers/supportsoftware/linux/hpadu-7.70-12.linux.rpm
wget -nd ftp://ftp.hp.com/pub/products/servers/supportsoftware/linux/hpsmh-2.1.7-168.linux.x86_64.rpm
sudo rpm -i --nodeps hpacucli-7.70-12.linux.rpm
sudo rpm -i --force hpadu-7.70-12.linux.rpm hpsmh-2.1.7-168.linux.x86_64.rpm
&lt;/pre&gt;
&lt;p&gt;The Array Configuration command line utility can be started with the command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo -i hpacucli
&lt;/pre&gt;
&lt;p&gt;The utility itself is quite user-friendly, and the help seems to be good. Just type &amp;quot;help&amp;quot; and you will find commands to show and modify your arrays. Some examples:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
=&amp;gt; ctrl all show status

Smart Array E200
   Controller Status: OK
   Cache Status: OK
   Battery Status: OK

=&amp;gt; ctrl all show config

Smart Array E200              (sn: PA6C90L9SV4152)

   array A (SATA, Unused Space: 0 MB)

      logicaldrive 1 (1.4 TB, RAID 5, OK)

      physicaldrive 1I:1:5 (port 1I:box 1:bay 5, SATA, 500.1 GB, OK)
      physicaldrive 1I:1:7 (port 1I:box 1:bay 7, SATA, 500.1 GB, OK)
      physicaldrive 2I:1:1 (port 2I:box 1:bay 1, SATA, 500.1 GB, OK)
      physicaldrive 2I:1:3 (port 2I:box 1:bay 3, SATA, 500.1 GB, OK)
&lt;/pre&gt;
&lt;p&gt;The utility also understands commands directly from the command line:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
$ sudo -i hpacucli ctrl serialnumber=PA6C90L9SV4152 array A show

Smart Array E200

   Array: A
      Interface Type: SATA
      Unused Space: 0 MB
      Status: OK
&lt;/pre&gt;
&lt;p&gt;To create a diagnostic report with the Array Diagnostic Utility, type:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
sudo /usr/sbin/hpaducli -f hpadu.report
&lt;/pre&gt;
&lt;p&gt;That will create a detailed diagnostic report into the file &amp;quot;hpadu.report&amp;quot;. You can use that report to check what has failed in case you controller or array status is not OK.&lt;/p&gt;
&lt;p&gt;I created a little script called &amp;quot;array_check&amp;quot; that can be added as a cron job to check that the array is healthy:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/bin/sh

/usr/sbin/hpacucli ctrl serialnumber=PA6C90L9SV4152 array A show status|grep -q &amp;quot;array A: OK&amp;quot;

if test &amp;quot;$?&amp;quot; != &amp;quot;0&amp;quot;
then
  echo Array A not ok!
  hpacucli ctrl serialnumber=PA6C90L9SV4152 array A show
  hpacucli ctrl serialnumber=PA6C90L9SV4152 show
  echo ------------------------------------------------------------
  echo
  /usr/sbin/hpaducli -f /tmp/hpadu.report
  cat /tmp/hpadu.report
fi
&lt;/pre&gt;
&lt;p&gt;Just add the script as a cron job and configure your machine to e-mail you the output of cron jobs, and you will get an e-mail if the status of the array changes.&lt;/p&gt;
</content><category term="Blog"></category><category term="CentOS"></category><category term="Hardware"></category><category term="HP Smart Array"></category><category term="Linux"></category><category term="ProLiant"></category><category term="Storage"></category></entry><entry><title>Lenovo ThinkPad X300 Ubuntu 8.04 Installation Notes</title><link href="https://mikko.kortelainen.io/blog/lenovo-thinkpad-x300-ubuntu-804-installation-notes/" rel="alternate"></link><published>2008-06-05T21:12:00+03:00</published><updated>2008-06-05T21:12:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-06-05:/blog/lenovo-thinkpad-x300-ubuntu-804-installation-notes/</id><summary type="html">&lt;p&gt;First, let me tell you some first impressions about the machine. The keyboard is
very good. It feels even a bit better than the one in my old T60. The display is
very bright and sharp, but viewing angles could be better. WLAN worked right out
of the box, as …&lt;/p&gt;</summary><content type="html">&lt;p&gt;First, let me tell you some first impressions about the machine. The keyboard is
very good. It feels even a bit better than the one in my old T60. The display is
very bright and sharp, but viewing angles could be better. WLAN worked right out
of the box, as did the webcam.&lt;/p&gt;
&lt;p&gt;The solid state drive is incredibly fast. I will never switch back to a hard
disk after experiencing an SSD. Everything loads up in an instance. OpenOffice
starts in about 5 seconds, which is very good compared to my T60. And the
machine boots up and shuts down really fast (I haven't timed those operations,
though).&lt;/p&gt;
&lt;p&gt;There are also a couple of annoyances which I hope will soon be fixed. Under
ubuntu, the fan keeps running at nearly 6000 RPM and makes a lot of noise. It
only stops when you let the machine settle a while with the display off, and
starts again almost immediately you start using it again. This is the most
annoying thing I can think of. Hopefully somebody finds a fix for this one. The
temperatures of various components remain reasonably low in my opinion.The CPU
runs at about 40&lt;/p&gt;
</content><category term="Blog"></category><category term="Hardware"></category><category term="Linux"></category><category term="ThinkPad"></category><category term="Ubuntu"></category></entry><entry><title>Limiting the bandwidth of incoming traffic</title><link href="https://mikko.kortelainen.io/blog/limiting-the-bandwidth-of-incoming-traffic/" rel="alternate"></link><published>2008-04-23T15:48:00+03:00</published><updated>2008-04-23T15:48:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-04-23:/blog/limiting-the-bandwidth-of-incoming-traffic/</id><summary type="html">&lt;p&gt;A backup server was saturating the DSL links of remote offices every time the
backups were running. To prevent this, I had to limit the incoming bandwidth of
the TCP-connections that were used to back up the remote hosts, but not touch
the ones that were used to connect to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A backup server was saturating the DSL links of remote offices every time the
backups were running. To prevent this, I had to limit the incoming bandwidth of
the TCP-connections that were used to back up the remote hosts, but not touch
the ones that were used to connect to the servers in the local network. Here's
how to do it.&lt;/p&gt;
&lt;p&gt;The limiting must be done by attaching a queuing discipline on the ingress side
of the interface the traffic is coming in from. After that you can attach
filters that filter traffic from specified hosts or subnets with a given
bandwidth.&lt;/p&gt;
&lt;p&gt;Step number one is to attach the ingress qdisc:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;srv:/# tc qdisc add dev eth0 handle ffff: ingress
&lt;/pre&gt;
&lt;p&gt;Step number two is to add one or more filters that police the bandwidth:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;srv:/# tc filter add dev eth0 parent ffff: protocol ip prio 50 \
            u32 match ip src 192.168.123.123 \
            police rate 64kbit burst 10k drop flowid :1
root&amp;#64;srv:/# tc filter add dev eth0 parent ffff: protocol ip prio 50 \
            u32 match ip src 192.168.124.0/24 \
            police rate 128kbit burst 10k drop flowid :1
&lt;/pre&gt;
&lt;p&gt;Step number three is to make your new qdisc and filters to load each time you
reboot your server. On Ubuntu, this can be achieved by adding a script to the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/network/if-up.d&lt;/span&gt;&lt;/tt&gt; directory. Scripts in that directory will be called
whenever a network interface comes up.&lt;/p&gt;
&lt;p&gt;Let's add a file called &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;/etc/network/if-up.d/tc&lt;/span&gt;&lt;/tt&gt; with the following contents:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/bin/sh
#
# Network traffic control settings
#

/sbin/tc qdisc add dev eth0 handle ffff: ingress
/sbin/tc filter add dev eth0 parent ffff: protocol ip prio 50 \
         u32 match ip src 192.168.123.123 \
         police rate 64kbit burst 10k drop flowid :1
/sbin/tc filter add dev eth0 parent ffff: protocol ip prio 50 \
         u32 match ip src 192.168.124.0/24 \
         police rate 128kbit burst 10k drop flowid :1
&lt;/pre&gt;
&lt;p&gt;Further reading:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.linuxdocs.org/HOWTOs/Adv-Routing-HOWTO-14.html"&gt;http://www.linuxdocs.org/HOWTOs/Adv-Routing-HOWTO-14.html&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://lartc.org/howto/"&gt;http://lartc.org/howto/&lt;/a&gt;&lt;/p&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="Networking"></category><category term="Ubuntu"></category></entry><entry><title>MediaWiki Image Links</title><link href="https://mikko.kortelainen.io/blog/mediawiki-image-links/" rel="alternate"></link><published>2008-04-14T16:02:00+03:00</published><updated>2008-04-14T16:02:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-04-14:/blog/mediawiki-image-links/</id><content type="html">&lt;p&gt;Here's a description how to do it without any extensions:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://distributedresearch.net/blog/2008/01/21/how-to-make-image-links-in-mediawiki"&gt;http://distributedresearch.net/blog/2008/01/21/how-to-make-image-links-in-mediawiki&lt;/a&gt;&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;This extension will allow you to use more comfortable markup:&lt;/div&gt;
&lt;div class="line"&gt;`
&lt;a class="reference external" href="http://www.mediawiki.org/wiki/Extension:ImageLink"&gt;http://www.mediawiki.org/wiki/Extension:ImageLink&lt;/a&gt; &amp;lt;&lt;a class="reference external" href="http://www.mediawiki.org/wiki/Extension:ImageLink"&gt;http://www.mediawiki.org/wiki/Extension:ImageLink&lt;/a&gt;&amp;gt;`__&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="MediaWiki"></category></entry><entry><title>Mounting Windows filesystems from AIX 5.3</title><link href="https://mikko.kortelainen.io/blog/mounting-windows-filesystems-from-aix-53/" rel="alternate"></link><published>2008-02-18T14:52:00+02:00</published><updated>2008-02-18T14:52:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-02-18:/blog/mounting-windows-filesystems-from-aix-53/</id><summary type="html">&lt;p&gt;First, you must install fileset &lt;em&gt;bos.cifs_fs.rte&lt;/em&gt;, and optionally &lt;em&gt;bos.cifs_fs.smit&lt;/em&gt; for the Smitty interface, from the installation DVD.&lt;/p&gt;
&lt;p&gt;To invoke the Smitty interface, run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root# smitty cifs_fs
&lt;/pre&gt;
&lt;p&gt;The Smitty interface will enable you to do almost anything you need with the CIFS filesystem.&lt;/p&gt;
&lt;p&gt;For people aligned the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;First, you must install fileset &lt;em&gt;bos.cifs_fs.rte&lt;/em&gt;, and optionally &lt;em&gt;bos.cifs_fs.smit&lt;/em&gt; for the Smitty interface, from the installation DVD.&lt;/p&gt;
&lt;p&gt;To invoke the Smitty interface, run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root# smitty cifs_fs
&lt;/pre&gt;
&lt;p&gt;The Smitty interface will enable you to do almost anything you need with the CIFS filesystem.&lt;/p&gt;
&lt;p&gt;For people aligned the command line way, mounting a share is a two-phase process. First, credentials must be added to the &lt;em&gt;/etc/cifs_fs/cifscred&lt;/em&gt; file. After that, you can mount a remote CIFS file system using the credentials specified. You could do the whole thing from the command line, but this is the preferred method in my opinion.&lt;/p&gt;
&lt;p&gt;SMBFS can store server/user/password credentials in the &lt;em&gt;/etc/cifs_fs/cifscred&lt;/em&gt; file to allow automatic retrieval of passwords when mounting SMBFS. Credentials can be added, changed, and removed from this file with the &lt;em&gt;mkcifscred&lt;/em&gt;, &lt;em&gt;chcifscred&lt;/em&gt;, and &lt;em&gt;rmcifscred&lt;/em&gt; commands.&lt;/p&gt;
&lt;p&gt;To add a credential:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root# mkcifscred -h &amp;lt;server&amp;gt; -u &amp;lt;user&amp;gt; -p &amp;lt;pass&amp;gt;
&lt;/pre&gt;
&lt;p&gt;Use the &lt;em&gt;mkcifsmnt&lt;/em&gt;, &lt;em&gt;chcifsmnt&lt;/em&gt;, &lt;em&gt;rmcifsmnt&lt;/em&gt;, and &lt;em&gt;lscifsmnt&lt;/em&gt; commands to add, change, remove, and list, respectively, cifs stanzas in &lt;em&gt;/etc/filesystems&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;To mount a file system:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root# mkdir -p /mount/point
root# mkcifsmnt -f /mount/point -h &amp;lt;server&amp;gt; -d &amp;lt;share&amp;gt; -c &amp;lt;user&amp;gt; -w &amp;lt;workgroup/domain&amp;gt;
&lt;/pre&gt;
&lt;p&gt;That will add a new stanza to &lt;em&gt;/etc/filesystems&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/mount/point:
        dev             = &amp;lt;share&amp;gt;
        vfs             = cifs
        nodename        = &amp;lt;server&amp;gt;/&amp;amp;lt:user&amp;gt;
        mount           = false
        options         = wrkgrp=&amp;lt;workgroup/domain&amp;gt;
        account         = false
&lt;/pre&gt;
&lt;p&gt;Automatical mounting during startup can be specified with the &lt;em&gt;-A&lt;/em&gt; option to &lt;em&gt;mkcifsmnt&lt;/em&gt;. You can give your mounted share a different set of permissions and owners with the &lt;em&gt;-u &amp;lt;uid&amp;gt;&lt;/em&gt;, &lt;em&gt;-g &amp;lt;gid&amp;gt;&lt;/em&gt; and the &lt;em&gt;-x &amp;lt;mode&amp;gt;&lt;/em&gt; options.&lt;/p&gt;
&lt;p&gt;Sources of information:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;a class="reference external" href="http://publib.boulder.ibm.com/infocenter/pseries/v5r3/index.jsp?topic=/com.ibm.aix.commadmn/doc/commadmndita/smbfs_intro.htm"&gt;pSeries and AIX Information Center: Server Message Block Filesystem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="reference external" href="http://publib.boulder.ibm.com/infocenter/pseries/v5r3/topic/com.ibm.aix.cmds/doc/aixcmds3/mkcifsmnt.htm?resultof=%22%6d%6b%63%69%66%73%6d%6e%74%22%20"&gt;pSeries and AIX Information Center: mkcifsmnt&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content><category term="Blog"></category><category term="AIX"></category><category term="Samba"></category><category term="UNIX"></category></entry><entry><title>Sqlite3 for ARMEL</title><link href="https://mikko.kortelainen.io/blog/sqlite3-for-armel/" rel="alternate"></link><published>2008-02-10T01:47:00+02:00</published><updated>2008-02-10T01:47:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-02-10:/blog/sqlite3-for-armel/</id><summary type="html">&lt;p&gt;Here's a statically compiled version of Sqlite 3.5.6 command line interface on
ARMEL with Readline support. It runs nicely on Nokia Internet Tablets with the
OS 2008 (libreadline4 must be installed):&lt;/p&gt;
&lt;p&gt;sqlite3-armel.gz &lt;em&gt;(download no longer available)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It was compiled with the following settings:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
./configure --disable-shared --enable-readline --enable-dynamic-extensions …&lt;/pre&gt;</summary><content type="html">&lt;p&gt;Here's a statically compiled version of Sqlite 3.5.6 command line interface on
ARMEL with Readline support. It runs nicely on Nokia Internet Tablets with the
OS 2008 (libreadline4 must be installed):&lt;/p&gt;
&lt;p&gt;sqlite3-armel.gz &lt;em&gt;(download no longer available)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;It was compiled with the following settings:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
./configure --disable-shared --enable-readline --enable-dynamic-extensions
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Maemo"></category><category term="Sqlite"></category></entry><entry><title>MS Exchange 2007 upgrade memo</title><link href="https://mikko.kortelainen.io/blog/ms-exchange-2007-upgrade-memo/" rel="alternate"></link><published>2008-01-14T10:20:00+02:00</published><updated>2008-01-14T10:20:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-01-14:/blog/ms-exchange-2007-upgrade-memo/</id><summary type="html">&lt;p&gt;This short list should apply to a situation where an organization with one domain and a simple Exchange environment wants to upgrade from Exchange 2003 to 2007. It assumes everything will be installed on a single server with a fresh installation of Windows 2003 R2, joined as a member server …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This short list should apply to a situation where an organization with one domain and a simple Exchange environment wants to upgrade from Exchange 2003 to 2007. It assumes everything will be installed on a single server with a fresh installation of Windows 2003 R2, joined as a member server into the domain.&lt;/p&gt;
&lt;p&gt;Software requirements:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Microsoft Internet Information Server&lt;/li&gt;
&lt;li&gt;.NET Framework 2.0 SP1&lt;/li&gt;
&lt;li&gt;Windows PowerShell&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Active Directory requirements:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;Forest Functional Level must be at least 2003&lt;/li&gt;
&lt;li&gt;Domain Function Level must be at least 2003&lt;/li&gt;
&lt;li&gt;Schema Master must be a Windows 2003 SP1 or newer&lt;/li&gt;
&lt;li&gt;Operations Master must be a Windows 2003 SP1 or newer&lt;/li&gt;
&lt;li&gt;Echange Server operation mode must be Native&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To prepare Active Directory, the following operations must be performed with the Setup.exe that is included in the Exchange Server installation media. Just run them from the command line.&lt;/p&gt;
&lt;ol class="arabic simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;setup /pl&lt;/tt&gt; -- short for /PrepareLegacyExchangePermissions&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;setup /ps&lt;/tt&gt; -- short for /PrepareSchema&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;setup /p&lt;/tt&gt; -- short for /PrepareAD&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;setup /pd&lt;/tt&gt; -- short for /PrepareDomain&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;After that, you are ready to run setup and start migrating mailboxes.&lt;/p&gt;
&lt;p&gt;The default installation installs Outlook Web Access into your Default Web Site under &lt;em&gt;/owa&lt;/em&gt;. A quick way to forward incoming http and https request to the server root directly into OWA login page can be done this way:&lt;/p&gt;
&lt;ol class="arabic"&gt;
&lt;li&gt;&lt;p class="first"&gt;Disable &amp;quot;Require secure channel (SSL)&amp;quot; from the Default Web Site properties&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Enable &amp;quot;Require secure channel (SSL)&amp;quot; from the &lt;em&gt;/owa&lt;/em&gt; folder properties&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Add a &amp;quot;Default.aspx&amp;quot; in the server root, with the following content:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
&amp;lt;%
response.redirect(&amp;quot;https://your.server.com/owa&amp;quot;)
%&amp;gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Recommended reading:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://technet.microsoft.com/en-us/library/bb124008.aspx"&gt;http://technet.microsoft.com/en-us/library/bb124008.aspx&lt;/a&gt;&lt;/p&gt;
</content><category term="Blog"></category><category term="Exchange"></category><category term="Windows"></category></entry><entry><title>Scratchbox installation under 32-bit chroot on 64-bit Ubuntu</title><link href="https://mikko.kortelainen.io/blog/scratchbox-installation-under-32-bit-chroot-on-64-bit-ubuntu/" rel="alternate"></link><published>2008-01-05T17:10:00+02:00</published><updated>2008-01-05T17:10:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2008-01-05:/blog/scratchbox-installation-under-32-bit-chroot-on-64-bit-ubuntu/</id><summary type="html">&lt;p&gt;I wanted to try out the &lt;a class="reference external" href="http://maemo.org/"&gt;Maemo&lt;/a&gt; &lt;a class="reference external" href="http://maemo.org/development/sdks/maemo_4_0_chinook_sdk.html"&gt;SDK&lt;/a&gt; for Nokia &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Nokia_770"&gt;770&lt;/a&gt;, &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Nokia_N800"&gt;N800&lt;/a&gt; and &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Nokia_N810"&gt;N810&lt;/a&gt; devices (for some reason I happen to own one of every generation), but found out that there are no prebuilt packages for the 64-bit environment. The quick (?) remedy for this is the chroot jail, because a …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I wanted to try out the &lt;a class="reference external" href="http://maemo.org/"&gt;Maemo&lt;/a&gt; &lt;a class="reference external" href="http://maemo.org/development/sdks/maemo_4_0_chinook_sdk.html"&gt;SDK&lt;/a&gt; for Nokia &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Nokia_770"&gt;770&lt;/a&gt;, &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Nokia_N800"&gt;N800&lt;/a&gt; and &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Nokia_N810"&gt;N810&lt;/a&gt; devices (for some reason I happen to own one of every generation), but found out that there are no prebuilt packages for the 64-bit environment. The quick (?) remedy for this is the chroot jail, because a guest i386 environment can pretty easily be bootstrapped inside a 64-bit one. Here are the step-by-step instructions for doing it.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="setting-up-the-chroot-jail-for-scratchbox"&gt;
&lt;h2&gt;Setting up the chroot jail for Scratchbox&lt;/h2&gt;
&lt;p&gt;The first thing to do is setting up a chroot environment with 32-bit binaries. This can be achieved nicely with &lt;em&gt;schroot&lt;/em&gt; and &lt;em&gt;debootstrap&lt;/em&gt;, which can be found in the Debian Universe. Debootstrap will download and install a basic Debian system into a directory. In this case, we will install Ubuntu Gutsy i386 under &lt;em&gt;/ubuntu32&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;T60:/# apt-get install schroot debootstrap
root&amp;#64;T60:/# mkdir /ubuntu32
root&amp;#64;T60:/# debootstrap --arch i386 gutsy /ubuntu32
I: Retrieving Release
I: Retrieving Packages
I: Validating Packages
.
.
.
root&amp;#64;T60:/# chroot /ubuntu32
&lt;/pre&gt;
&lt;p&gt;That last command will actually &lt;em&gt;chroot&lt;/em&gt; you into the directory &lt;tt class="docutils literal"&gt;/ubuntu32&lt;/tt&gt;. What that means in practise is that your new root directory will be in fact /ubuntu32, and your new shell will be restricted under that directory. In effect, what you see as the root directory / will in reality reside under /ubuntu32. There is no easy way to see whether you're inside a jail or not, and the purpose of this is of course to trick programs into thinking they are running on another system. To escape the &lt;em&gt;chroot jail&lt;/em&gt;, just say &lt;tt class="docutils literal"&gt;exit&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;The newly bootstrapped system is very bare. Indeed there is no locale support until you install it. That should probably be the first thing to do. My locale is Finnish, so I will install the &lt;em&gt;language-pack-fi&lt;/em&gt; package. After that, let's install the &lt;em&gt;Nano&lt;/em&gt; editor, and edit our Apt sources:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;chroot:/# apt-get install language-pack-fi
root&amp;#64;chroot:/# apt-get install nano
root&amp;#64;chroot:/# nano -w /etc/apt/sources.list
&lt;/pre&gt;
&lt;p&gt;I make the &lt;em&gt;sources.list&lt;/em&gt; look like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
deb http://archive.ubuntu.com/ubuntu gutsy main restricted universe multiverse
&lt;/pre&gt;
&lt;p&gt;A couple more things to do before our chroot is ready. We must set up user accounts and mounts. If you are happy running as the root user, there is no need to do anything, but I wanted to add an account for myself. The easiest way is to copy all necessary information from your existing /etc outside the chroot:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;T60:/etc# cp passwd shadow group gshadow sudoers hosts resolv.conf /ubuntu32/etc/
&lt;/pre&gt;
&lt;p&gt;That way your password, groups and all other settings are preserved without problems. You can add that command to cron if you want them synchronized automatically.&lt;/p&gt;
&lt;p&gt;Next, you need to mount a couple of filesystems to make things go smoothly. Such are &lt;em&gt;/proc&lt;/em&gt;, &lt;em&gt;/sys&lt;/em&gt; and &lt;em&gt;/dev&lt;/em&gt;, and also possibly &lt;em&gt;/home&lt;/em&gt; and &lt;em&gt;/tmp&lt;/em&gt;. The first three are needed for correct operation of many programs, while the latter two will ease your use of the chroot environment.&lt;/p&gt;
&lt;p&gt;The create the mounts, add these lines to the &lt;em&gt;/etc/fstab&lt;/em&gt; &lt;strong&gt;OUTSIDE&lt;/strong&gt; the chroot (your normal fstab):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# chroot binds:

/home  /ubuntu32/home   none   bind     0 0
/tmp   /ubuntu32/tmp    none   bind     0 0
/dev   /ubuntu32/dev    none   bind     0 0
proc   /ubuntu32/proc   proc   defaults 0 0
sysfs  /ubuntu32/sys    sysfs  defaults 0 0
&lt;/pre&gt;
&lt;p&gt;I mounted them right away with the &lt;tt class="docutils literal"&gt;mount &lt;span class="pre"&gt;-a&lt;/span&gt;&lt;/tt&gt; command.&lt;/p&gt;
&lt;p&gt;The last thing to do is make the chroot accessible for the general user. This is where &lt;em&gt;schroot&lt;/em&gt; comes into play. It's purpose is to make normal users able to chroot themselves into jails predefined by root. Let's add a chroot jail into &lt;em&gt;/etc/schroot/scroot.conf&lt;/em&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[ubuntu32]
description=Gutsy Gibbon i386
location=/ubuntu32
users=mkortela
aliases=scratchbox,default
&lt;/pre&gt;
&lt;p&gt;Now, user mkortela is able to chroot into our new environment:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~$ schroot ubuntu32
I: [ubuntu32 chroot] Running login shell: '/bin/bash'
mkortela&amp;#64;T60:~$
&lt;/pre&gt;
&lt;p&gt;Now we are in the chroot jail as ourselves, and able to sudo as we were outside the jail. Also, the user's home directory is right where it is supposed to be. To remember we are inside the chroot, it may be a good idea to change the prompt a little bit:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~$ export PS1='${debian_chroot:+($debian_chroot)}u&amp;#64;chroot:w$ '
mkortela&amp;#64;chroot:~$
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="scratchbox-installation-inside-the-chroot-jail"&gt;
&lt;h2&gt;Scratchbox installation inside the chroot jail&lt;/h2&gt;
&lt;p&gt;The Scratchbox installation will go pretty much like described in the &lt;a class="reference external" href="http://tablets-dev.nokia.com/4.0/INSTALL.txt"&gt;INSTALL.txt&lt;/a&gt;. There are a couple of extra tweaks, though. First, lets fetch the installation scripts, and run them. First the Scratchbox installation, then the SDK installation. The installation scripts will have to be cheated with the &lt;tt class="docutils literal"&gt;linux32&lt;/tt&gt; command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;chroot:~$ sudo apt-get install wget
mkortela&amp;#64;chroot:~$ wget http://tablets-dev.nokia.com/4.0/maemo-scratchbox-install_4.0.sh
mkortela&amp;#64;chroot:~$ wget http://tablets-dev.nokia.com/4.0/maemo-sdk-install_4.0.sh
mkortela&amp;#64;chroot:~$ chmod a+x maemo-scratchbox-install_4.0.sh
mkortela&amp;#64;chroot:~$ chmod a+x maemo-sdk-install_4.0.sh
mkortela&amp;#64;chroot:~$ linux32 sudo ./maemo-scratchbox-install_4.0.sh
.
.
.
Installation was successful!
----------------------------

You now have Scratchbox 1.0.8 'apophis' release installed.

Scratchbox cannot be run as user root. Instead, use your normal login
user account. Add additional scratchbox users and sandboxes with the
following command (outside scratchbox with root permissions):

        # /scratchbox/sbin/sbox_adduser USER yes

Running this command will create sandbox environment for that user and
add user to the 'sbox' scratchbox user group.
You will need to start a new login terminal after being added to the
'sbox' group for group membership to be effective.

Login to scratchbox session using the following command (as user):

        $ /scratchbox/login

Refer to scratchbox.org documentation for more information re scratchbox:
http://scratchbox.org/documentation/user/scratchbox-1.0/
&lt;/pre&gt;
&lt;p&gt;Let's do what they ask:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;chroot:~$ sudo /scratchbox/sbin/sbox_adduser mkortela yes
Adding user `mkortela' to group `sbox' ...
Done.
Scratchbox user account for user mkortela added
&lt;/pre&gt;
&lt;p&gt;And let's create the group outside the chroot and add ourselves there as well:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;T60:/# groupadd -g 1001 sbox
root&amp;#64;T60:/# usermod -a -G sbox mkortela
&lt;/pre&gt;
&lt;p&gt;And now, the SDK installation:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;chroot:~$ linux32 ./maemo-sdk-install_4.0.sh
&lt;/pre&gt;
&lt;p&gt;I installed with the default options, although I decided to download the non-free Nokia packages as well.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="installing-and-running-xephyr"&gt;
&lt;h2&gt;Installing and running Xephyr&lt;/h2&gt;
&lt;p&gt;Xephyr can be installed directly from the universe. We will install it outside the chroot environment, because that's where all our X libraries and fonts are:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;T60:/# apt-get install xserver-xephyr
&lt;/pre&gt;
&lt;p&gt;Let's check that it runs as a regular user:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~$ Xephyr :2 -host-cursor -screen 800x480x16 -dpi 96 -ac -extension Composite
&lt;/pre&gt;
&lt;p&gt;You should get a Window with a simple X session (just the default boring wallpaper and nothing else). To start the Maemo default programs in it, open another shell window, go inside the chroot, and run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;chroot:~$ sudo /etc/init.d/scratchbox-core start
mkortela&amp;#64;chroot:~$ sb-conf select CHINOOK_X86
mkortela&amp;#64;chroot:~$ scratchbox
[sbox-CHINOOK_X86: ~] &amp;gt; export DISPLAY=:2
[sbox-CHINOOK_X86: ~] &amp;gt; af-sb-init.sh start
&lt;/pre&gt;
&lt;p&gt;You should be able to see a very basic Maemo session, similar to the one shown in the &lt;a class="reference external" href="http://maemo.org/development/documentation/tutorials/maemo_4-0_tutorial.html#settingup"&gt;Maemo 4.0 Tutorial&lt;/a&gt;. That document is also a good place to continue from here on.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="Maemo"></category><category term="Ubuntu"></category></entry><entry><title>SUID script requirements on AIX 5L and ksh93</title><link href="https://mikko.kortelainen.io/blog/suid-script-requirements-on-aix-5l-and-ksh93/" rel="alternate"></link><published>2007-11-30T16:45:00+02:00</published><updated>2007-11-30T16:45:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-11-30:/blog/suid-script-requirements-on-aix-5l-and-ksh93/</id><summary type="html">&lt;p&gt;Requirements for a suid script include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;#! directing the KornShell be used&lt;/li&gt;
&lt;li&gt;Executable by user, group, and other&lt;/li&gt;
&lt;li&gt;No read permission&lt;/li&gt;
&lt;li&gt;Add suid permission by chmod u+s on the file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add a -p option to #! to increase security to force a separate process if one is
not normally done.&lt;/p&gt;
&lt;p&gt;Example …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Requirements for a suid script include:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;#! directing the KornShell be used&lt;/li&gt;
&lt;li&gt;Executable by user, group, and other&lt;/li&gt;
&lt;li&gt;No read permission&lt;/li&gt;
&lt;li&gt;Add suid permission by chmod u+s on the file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Add a -p option to #! to increase security to force a separate process if one is
not normally done.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#! /usr/bin/ksh -p
&lt;/pre&gt;
&lt;p&gt;Source of this information:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.ibm.com/developerworks/aix/library/au-kornshell93.html#n"&gt;http://www.ibm.com/developerworks/aix/library/au-kornshell93.html#n&lt;/a&gt;&lt;/p&gt;
</content><category term="Blog"></category><category term="AIX"></category><category term="Shell scripts"></category><category term="UNIX"></category></entry><entry><title>Enabling security on an HP ProCurve 4200 series switch</title><link href="https://mikko.kortelainen.io/blog/enabling-security-on-an-hp-procurve-4200-series-switch/" rel="alternate"></link><published>2007-11-03T15:34:00+02:00</published><updated>2007-11-03T15:34:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-11-03:/blog/enabling-security-on-an-hp-procurve-4200-series-switch/</id><summary type="html">&lt;p&gt;I had a chance to configure an HP ProCurve 4208vl switch the other day. The first impression was that the command line interface is heavily influenced by, if not directly copied from, the Cisco IOS command line interface. So if you have experience with IOS, you will probably feel almost …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I had a chance to configure an HP ProCurve 4208vl switch the other day. The first impression was that the command line interface is heavily influenced by, if not directly copied from, the Cisco IOS command line interface. So if you have experience with IOS, you will probably feel almost at home on an HP switch. There are some differences, though.&lt;/p&gt;
&lt;p&gt;The first thing I wanted to do was to enable ssh access and authentication, and disable telnet. Here's a quick howto.&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div class="line"&gt;Connect to the switch using the console cable or telnet.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;First thing to do is to enter the configuration mode and generate a key for ssh. Only after the key has been generated is it possible to enable ssh:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ProCurve Switch 4208vl# configure
ProCurve Switch 4208vl(config)# crypto key generate ssh
depleted, this could take up to a minute.
ProCurve Switch 4208vl(config)# ip ssh
ProCurve Switch 4208vl(config)# ip ssh filetransfer
ProCurve Switch 4208vl(config)# end
&lt;/pre&gt;
&lt;p&gt;That is not enough, however. You must set the operator and manager passwords to actually authenticate to the switch.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ProCurve Switch 4208vl# configure
ProCurve Switch 4208vl(config)# password manager
New password for Manager:
Please retype new password for Manager:
ProCurve Switch 4208vl(config)# password operator
New password for Operator:
Please retype new password for Operator:
ProCurve Switch 4208vl(config)# end
&lt;/pre&gt;
&lt;p&gt;After the above changes, the web interface will also require a password. For some reason, you must leave the username field empty and input either the manager or the operator password in the password field.&lt;/p&gt;
&lt;p&gt;To disable the telnet server:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ProCurve Switch 4208vl# configure
ProCurve Switch 4208vl(config)# no telnet-server
ProCurve Switch 4208vl(config)# end
&lt;/pre&gt;
&lt;p&gt;To create a key and a self-signed certificate for SSL web access:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ProCurve Switch 4208vl(config)# crypto key generate cert 1024
Installing new RSA key.  If the key/entropy cache is
depleted, this could take up to a minute.
ProCurve Switch 4208vl(config)# crypto host-cert generate self-signed 11/01/2007 11/01/2017 sw1.koo.fi _ Techelp Helsinki _ fi
ProCurve Switch 4208vl(config)# web-management ssl
ProCurve Switch 4208vl(config)# aaa authentication web login local
ProCurve Switch 4208vl(config)# end
&lt;/pre&gt;
&lt;p&gt;Write your configuration changes:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ProCurve Switch 4208vl# write memory
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Networking"></category><category term="ProCurve"></category></entry><entry><title>Installing MySQL 5 on IBM AIX 5.3</title><link href="https://mikko.kortelainen.io/blog/installing-mysql-5-on-ibm-aix-53/" rel="alternate"></link><published>2007-11-02T12:40:00+02:00</published><updated>2007-11-02T12:40:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-11-02:/blog/installing-mysql-5-on-ibm-aix-53/</id><summary type="html">&lt;p&gt;The IBM AIX Software Toolbox download page includes a package for MySQL 3.23, but that was a little bit too aged for my purposes. Fortunately MySQL distributes binaries for IBM AIX here:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://dev.mysql.com/downloads/mysql/5.0.html#aix"&gt;http://dev.mysql.com/downloads/mysql/5.0.html#aix&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That package will work out of the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The IBM AIX Software Toolbox download page includes a package for MySQL 3.23, but that was a little bit too aged for my purposes. Fortunately MySQL distributes binaries for IBM AIX here:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div class="line"&gt;&lt;a class="reference external" href="http://dev.mysql.com/downloads/mysql/5.0.html#aix"&gt;http://dev.mysql.com/downloads/mysql/5.0.html#aix&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;That package will work out of the box with 5.3 as well. Download it, and unpack it to /usr/local:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;server# cat mysql-5.0.45-aix5.2-powerpc-64bit.tar.gz|gunzip|tar xvC /usr/local
root&amp;#64;server# ln -s /usr/local/mysql-5.0.45-aix5.2-powerpc-64bit /usr/local/mysql
&lt;/pre&gt;
&lt;p&gt;There is a file named &lt;em&gt;INSTALL-BINARY&lt;/em&gt; which includes these instructions as well as some more information, but here's a quick overview of the things you need to take care of.&lt;/p&gt;
&lt;p&gt;Create a user and group for privilege separation:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;server# groupadd mysql
root&amp;#64;server# useradd -g mysql mysql
root&amp;#64;server# chown -R mysql:mysql /usr/local/mysql-5.0.45-aix5.2-powerpc-64bit
&lt;/pre&gt;
&lt;p&gt;Create the MySQL data directory and initialize the grant tables:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;server# cd /usr/local/mysql
root&amp;#64;server# ./scripts/mysql_install_db --user=mysql
&lt;/pre&gt;
&lt;p&gt;Only the data directory need to be owned by the &lt;em&gt;mysql&lt;/em&gt; user, so for security reasons, we will give all other files back to root:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;server# chown -R root /usr/local/mysql-5.0.45-aix5.2-powerpc-64bit
root&amp;#64;server# chown -R mysql /usr/local/mysql-5.0.45-aix5.2-powerpc-64bit/data
&lt;/pre&gt;
&lt;p&gt;Start it up:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;server# /usr/local/mysql/bin/mysqld_safe --user=mysql &amp;amp;
&lt;/pre&gt;
</content><category term="Blog"></category><category term="AIX"></category><category term="MySQL"></category><category term="UNIX"></category></entry><entry><title>IBM Websphere Application Server 5.1 init script for Linux</title><link href="https://mikko.kortelainen.io/blog/ibm-websphere-application-server-51-init-script-for-linux/" rel="alternate"></link><published>2007-11-02T12:13:00+02:00</published><updated>2007-11-02T12:13:00+02:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-11-02:/blog/ibm-websphere-application-server-51-init-script-for-linux/</id><summary type="html">&lt;p&gt;WAS does not seem to install any default init scripts, so I created one. You can configure it to start and stop multiple application servers by listing them all in the APPSERVERS variable (separated by spaces).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/bin/sh
# chkconfig: 35 99 10
# description: Starts and stops Websphere Application Server

. /lib …&lt;/pre&gt;</summary><content type="html">&lt;p&gt;WAS does not seem to install any default init scripts, so I created one. You can configure it to start and stop multiple application servers by listing them all in the APPSERVERS variable (separated by spaces).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/bin/sh
# chkconfig: 35 99 10
# description: Starts and stops Websphere Application Server

. /lib/lsb/init-functions

# Please edit these variables to match your environment. You may list one or more
# application servers separated by spaces in the APPSERVERS variable.

OWNER=wasadmin
USERNAME=wasuser
PASSWORD=secret
APPSERVERS=&amp;quot;Appserver1&amp;quot;

WASDIR=/opt/WebSphere/AppServer
DMGRDIR=/opt/WebSphere/DeploymentManager
LOCKDIR=/var/lock/subsys

DMGRLOCK=&amp;quot;$LOCKDIR/WAS_deploymentmgr&amp;quot;
NODEAGENTLOCK=&amp;quot;$LOCKDIR/WAS_nodeagent&amp;quot;

# Don't edit beyond this point.

start_dmgr() {
  MSG=&amp;quot;Starting WAS Deployment Manager&amp;quot;
  [[ ! -e $DMGRLOCK ]] \
      &amp;amp;&amp;amp; su - $OWNER -c &amp;quot;$DMGRDIR/bin/startManager.sh -user $USERNAME -password $PASSWORD&amp;quot; \
      &amp;amp;&amp;amp; touch $DMGRLOCK \
      &amp;amp;&amp;amp; log_success_msg $MSG \
      || log_failure_msg $MSG
}

stop_dmgr() {
  MSG=&amp;quot;Stopping WAS Deployment Manager&amp;quot;
  [[ -e $DMGRLOCK ]] \
    &amp;amp;&amp;amp; [[ -e &amp;quot;$DMGRDIR/bin/stopManager.sh&amp;quot; ]] \
      &amp;amp;&amp;amp; su - $OWNER -c &amp;quot;$DMGRDIR/bin/stopManager.sh -user $USERNAME -password $PASSWORD&amp;quot; \
      &amp;amp;&amp;amp; rm -f $DMGRLOCK \
      &amp;amp;&amp;amp; log_success_msg $MSG \
      || log_failure_msg $MSG
}

start_nodeagent() {
  MSG=&amp;quot;Starting WAS Node Agent&amp;quot;
  [[ ! -e $NODEAGENTLOCK ]] \
    &amp;amp;&amp;amp; su - $OWNER -c &amp;quot;$WASDIR/bin/startNode.sh -user $USERNAME -password $PASSWORD&amp;quot; \
    &amp;amp;&amp;amp; touch $NODEAGENTLOCK \
    &amp;amp;&amp;amp; log_success_msg $MSG \
    || log_failure_msg $MSG
}

stop_nodeagent() {
  MSG=&amp;quot;Starting WAS Node Agent&amp;quot;
  [[ -e $NODEAGENTLOCK ]] \
    &amp;amp;&amp;amp; su - $OWNER -c &amp;quot;$WASDIR/bin/stopNode.sh -user $USERNAME -password $PASSWORD&amp;quot; \
    &amp;amp;&amp;amp; rm -f $NODEAGENTLOCK \
    &amp;amp;&amp;amp; log_success_msg $MSG \
    || log_failure_msg $MSG
}

start_appservers() {
  for WAS in $APPSERVERS
  do
    MSG=&amp;quot;Starting WAS: $WAS&amp;quot;
    LOCK=&amp;quot;$LOCKDIR/WAS_$WAS&amp;quot;
    [[ ! -e $LOCK ]] \
      &amp;amp;&amp;amp; su - $OWNER -c &amp;quot;$WASDIR/bin/startServer.sh $WAS -user $USERNAME -password $PASSWORD&amp;quot; \
      &amp;amp;&amp;amp; touch $LOCK \
      &amp;amp;&amp;amp; log_success_msg $MSG \
      || log_failure_msg $MSG
  done
}

stop_appservers() {
  for WAS in $APPSERVERS
  do
    MSG=&amp;quot;Stopping WAS: $WAS&amp;quot;
    LOCK=&amp;quot;$LOCKDIR/WAS_$WAS&amp;quot;
    [[ -e $LOCK ]] \
      &amp;amp;&amp;amp; su - $OWNER -c &amp;quot;$WASDIR/bin/stopServer.sh $WAS -user $USERNAME -password $PASSWORD&amp;quot; \
      &amp;amp;&amp;amp; rm -f $LOCK \
      &amp;amp;&amp;amp; log_success_msg $MSG \
      || log_failure_msg $MSG
  done
}


case &amp;quot;$1&amp;quot; in
  'start')   [[ -e &amp;quot;$DMGRDIR/bin/startManager.sh&amp;quot; ]] &amp;amp;&amp;amp; start_dmgr
             start_nodeagent
             start_appservers ;;
  'stop')    stop_appservers
             stop_nodeagent
             [[ -e &amp;quot;$DMGRDIR/bin/startManager.sh&amp;quot; ]] &amp;amp;&amp;amp; stop_dmgr ;;
  'restart') stop_appservers
             stop_nodeagent
             [[ -e &amp;quot;$DMGRDIR/bin/startManager.sh&amp;quot; ]] &amp;amp;&amp;amp; stop_dmgr
             sleep 5
             [[ -e &amp;quot;$DMGRDIR/bin/startManager.sh&amp;quot; ]] &amp;amp;&amp;amp; start_dmgr
             start_nodeagent
             start_appservers ;;
  'status')  [[ -e $DMGRLOCK ]] \
               &amp;amp;&amp;amp; echo WAS Deployment Manager is running (lockfile $DMGRLOCK) \
               || echo WAS Deployment Manager is stopped (no lockfile)
             [[ -e $NODEAGENTLOCK ]]
               &amp;amp;&amp;amp; echo WAS Node Agent is running (lockfile $NODEAGENTLOCK) \
               || echo WAS Node Agent is stopped (no lockfile)
             for WAS in $APPSERVERS
             do
               LOCK=&amp;quot;$LOCKDIR/WAS_$WAS&amp;quot;
               [[ -e $LOCK ]] \
                 &amp;amp;&amp;amp; echo WAS $WAS is running (lockfile $LOCK) \
                 || echo WAS $WAS is stopped (no lockfile)
             done
             $WASDIR/bin/serverStatus.sh -all -user $USERNAME -password $PASSWORD
             ;;
  *)         echo &amp;quot;Usage: was (start|stop|restart|status)&amp;quot;
             exit 1 ;;
esac
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="Red Hat"></category><category term="Websphere"></category></entry><entry><title>WPA-PSK authentication with Cisco IOS</title><link href="https://mikko.kortelainen.io/blog/wpa-psk-authentication-with-cisco-ios/" rel="alternate"></link><published>2007-10-26T20:50:00+03:00</published><updated>2007-10-26T20:50:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-10-26:/blog/wpa-psk-authentication-with-cisco-ios/</id><summary type="html">&lt;p&gt;When my Linux firewall box died a couple of months ago, I finally decided to by
a Cisco router for my Internet connection. Before the Linux box I had an OpenBSD
firewall, and I decided it was time to learn yet another platform.&lt;/p&gt;
&lt;p&gt;The box is a Cisco 877W which …&lt;/p&gt;</summary><content type="html">&lt;p&gt;When my Linux firewall box died a couple of months ago, I finally decided to by
a Cisco router for my Internet connection. Before the Linux box I had an OpenBSD
firewall, and I decided it was time to learn yet another platform.&lt;/p&gt;
&lt;p&gt;The box is a Cisco 877W which has one ADSL interface, a four-port ethernet
switch, and an 802.11g wireless NIC. My first impressions have been very
positive. I have for instance learned that this thing can easily be configured
to serve multiple SSIDs with different security settings from the same radio,
and the SSIDs can be attached to separate VLANs. That means I could create one
encrypted SSID for my private use, and an open one for passers by.&lt;/p&gt;
&lt;p&gt;Anyway, here's a quick configuration example. It creates an 802.11g interface
which is WPA-PSK protected and bridged to the 4-port ethernet switch:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
interface Dot11Radio0
 no ip address
 !
 encryption mode ciphers tkip
 !
 ssid Koo
    authentication open
    authentication key-management wpa
    guest-mode
    wpa-psk ascii 7 XXXXXSECRETXXXXSTRINGXXXXX
 !
 speed basic-1.0 2.0 5.5 6.0 9.0 11.0 12.0 18.0 24.0 36.0 48.0 54.0
 station-role root
 bridge-group 1
 bridge-group 1 spanning-disabled
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Cisco"></category><category term="Networking"></category></entry><entry><title>IBM SDD driver troubleshooting on Linux</title><link href="https://mikko.kortelainen.io/blog/ibm-sdd-driver-troubleshooting-on-linux/" rel="alternate"></link><published>2007-10-26T16:35:00+03:00</published><updated>2007-10-26T16:35:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-10-26:/blog/ibm-sdd-driver-troubleshooting-on-linux/</id><summary type="html">&lt;p&gt;&lt;a class="reference external" href="http://www-304.ibm.com/jct01004c/systems/support/supportsite.wss/supportresources?brandind=5000033&amp;amp;familyind=5329528&amp;amp;taskind=1"&gt;The Subsystem Device Driver [SDD]&lt;/a&gt; is a pseudo device driver designed to support the multipath configuration environments in the IBM TotalStorage Enterprise Storage Server, the IBM TotalStorage DS family, the IBM SystemStorage SAN Volume Controller. It resides in a host system with the native disk device driver and provides the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a class="reference external" href="http://www-304.ibm.com/jct01004c/systems/support/supportsite.wss/supportresources?brandind=5000033&amp;amp;familyind=5329528&amp;amp;taskind=1"&gt;The Subsystem Device Driver [SDD]&lt;/a&gt; is a pseudo device driver designed to support the multipath configuration environments in the IBM TotalStorage Enterprise Storage Server, the IBM TotalStorage DS family, the IBM SystemStorage SAN Volume Controller. It resides in a host system with the native disk device driver and provides the following functions:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;- Enhanced data availability&lt;/div&gt;
&lt;div class="line"&gt;- Dynamic I/O load-balancing across multiple paths&lt;/div&gt;
&lt;div class="line"&gt;- Automatic path failover protection&lt;/div&gt;
&lt;div class="line"&gt;- Concurrent download of licensed internal code&lt;/div&gt;
&lt;div class="line"&gt;- Path-selection policies for the host system&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;On AIX it works pretty much out-of-the-box, but on Linux the story is quite different. The driver is closed-source, so all you can do is download the driver kernel module for supported kernels from IBM, as well as some userspace software.&lt;/p&gt;
&lt;p&gt;For supported distributions, the driver can be downloaded from:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www-1.ibm.com/support/docview.wss?rs=540&amp;amp;context=ST52G7&amp;amp;dc=D430&amp;amp;uid=ssg1S4000107&amp;amp;loc=en_US&amp;amp;cs=utf-8&amp;amp;lang=en"&gt;Subsystem Device Driver for Linux&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;When you install the package, it copies its files under /opt/IBMsdd (at least the Redhat .rpms do). Also, it adds an init script called &amp;quot;sdd&amp;quot; under /etc/init.d, and adds a line like this in inittab:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
srv:345:respawn:/opt/IBMsdd/bin/sddsrv &amp;gt; /dev/null 2&amp;gt;&amp;amp;1
&lt;/pre&gt;
&lt;p&gt;That should take care that if the sddsrv daemon dies, it will be restarted automatically.&lt;/p&gt;
&lt;div class="section" id="basic-configuration"&gt;
&lt;h2&gt;Basic configuration&lt;/h2&gt;
&lt;p&gt;After the disks have been configured in the SAN Volume Controller, they should show up when the busses of the Fibre Channel adapters are re-scanned.&lt;/p&gt;
&lt;p&gt;/proc/partitions shows the new disk:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
252     0   73400320 vpatha
&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;/etc/vpath.conf&lt;/em&gt; holds the names for the device ID's, and &lt;em&gt;/etc/sddsrv.conf&lt;/em&gt; some miscellaneous settings.&lt;/p&gt;
&lt;p&gt;Under &lt;em&gt;/opt/IBMsdd/bin&lt;/em&gt; there are some useful utilities. The &lt;em&gt;datapath&lt;/em&gt; command will allow you to query adapters and devices, and set them offline or online. &lt;em&gt;lsvpcg&lt;/em&gt; shows which scsi disks map to which vpath disks. &lt;em&gt;cfgvpath&lt;/em&gt; allows you to make changes to the configuration.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="using-with-lvm-on-rhel4"&gt;
&lt;h2&gt;Using with LVM on RHEL4&lt;/h2&gt;
&lt;p&gt;To get LVM working correctly with SDD on RHEL4, there are a couple of things that must be taken care of.&lt;/p&gt;
&lt;div class="section" id="boot-up-load-order"&gt;
&lt;h3&gt;Boot-up load order&lt;/h3&gt;
&lt;p&gt;The first thing is to make sure the sdd driver loads before LVM on boot-up. The SDD User Manual suggests adding a script to start sdd in &lt;em&gt;/etc/rc.sysinit&lt;/em&gt;. It must be started after the root filesystem has been remounted but before LVM initializes:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#  Remount  the  root  filesystem  read-write.
update_boot_stage  RCmountfs
state=`awk  /  /  /  &amp;amp;&amp;amp;  ($3  !~  /rootfs/)  {  print  $4  }  /proc/mounts`
[  &amp;quot;$state&amp;quot;  !=  &amp;quot;rw&amp;quot;  -a  &amp;quot;$READONLY&amp;quot;  !=  &amp;quot;yes&amp;quot;  ]  &amp;amp;&amp;amp;
action  $&amp;quot;Remounting  root  filesystem  in  read-write  mode:  &amp;quot;  mount  -n  -o  remount,rw  /

#  Starting  SDD
/etc/init.d/sdd start

#  LVM  initialization
...
&lt;/pre&gt;
&lt;p&gt;Also, they say /etc/init.d/sdd script must be set _not_ to start at boot-up:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[root&amp;#64;server ~]# chkconfig sdd off
&lt;/pre&gt;
&lt;p&gt;The above configuration has a problem, though. The SDD software is installed under /opt, but if your /opt is on an LVM partition, there is no way to load the SDD drivers from there before LVM has been started and /opt mounted. In fact, if the line sits there, it will not work if /opt resides on its own partition of any type.&lt;/p&gt;
&lt;p&gt;One solution to that problem is to move the SDD drivers to the root partition. For me it seems to just work if I enable &lt;em&gt;/etc/init.d/sdd&lt;/em&gt; at bootup (no changes needed in rc.sysinit):&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[root&amp;#64;server ~]# chkconfig sdd on
&lt;/pre&gt;
&lt;p&gt;This may be due to the fact that my root partition is also in LVM, so that it has to be initialized in initrd early, and perhaps LVM scans for devices again later on.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="volume-initialization-and-detection-problems"&gt;
&lt;h3&gt;Volume initialization and detection problems&lt;/h3&gt;
&lt;p&gt;A couple of changes must be made to the LVM configuration file &lt;em&gt;/etc/lvm/lvm.conf&lt;/em&gt;. If you don't do that, you will run into an error message like this while trying to create a physical volume on a vpath device:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[root&amp;#64;server ~]# pvcreate /dev/vpatha1
  Device /dev/vpatha1 not found (or ignored by filtering).
&lt;/pre&gt;
&lt;div class="section" id="accepting-vpath-devices"&gt;
&lt;h4&gt;Accepting vpath devices&lt;/h4&gt;
&lt;p&gt;In /etc/lvm/lvm.conf, you will see that this line is commented out:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
# types = [ &amp;quot;fd&amp;quot;, 16 ]
&lt;/pre&gt;
&lt;p&gt;Remove the comment character, and change the line to look like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
types = [ &amp;quot;vpath&amp;quot;, 16 ]
&lt;/pre&gt;
&lt;p&gt;That will add vpath to LVM's list of accepted device types.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="rejecting-the-underlying-devices"&gt;
&lt;h4&gt;Rejecting the underlying devices&lt;/h4&gt;
&lt;p&gt;The lvm.conf has a &lt;em&gt;filter&lt;/em&gt; configuration option which is used to select the devices that are allowed to be used as LVM physical volumes. The default is usually to allow every device. That is a problem with vpath devices, however, because they will show up both as /dev/vpathX, and as regular scsi disks. So, if you have configured one disk per volume controller through two FC switches, you will see a total four /dev/sdX disks per one vpath disk. And all these five devices will show the same data (although only the vpath device is redundant, and should therefore be used). The LVM default is to scan all devices, so it will print error messages of duplicate physical volumes if you don't change the filtering rule. The messages look like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
Found duplicate PV 1XlJrZHnI49tTtHVvwe7cXZ0cATNFTxw: using /dev/sdak not /dev/vpatha
&lt;/pre&gt;
&lt;p&gt;This is particularly bad, as it means LVM has chosen to use sdak instead of the redundant vpatha path.&lt;/p&gt;
&lt;p&gt;To prevent this, change the filter line in lvm.conf to look like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
filter  =  [  &amp;quot;a/vpath[a-z]*/&amp;quot;,  &amp;quot;r/.*/&amp;quot;  ]
&lt;/pre&gt;
&lt;p&gt;That line means LVM accepts only devices named vpath[a-z]*. This way LVM will choose the correct device. However, if you have physical volumes on internal SCSI disks, that line will also reject them. Add an accept rule on those:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
filter  =  [  &amp;quot;a/vpath[a-z]*/&amp;quot;, &amp;quot;a/sda2/&amp;quot;, &amp;quot;r/.*/&amp;quot;  ]
&lt;/pre&gt;
&lt;p&gt;After these changes, you should be able to create a physical volume on vpath devices, and no error messages should be displayed when handing volumes. And everything should look the same the next time you boot.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="Red Hat"></category><category term="Storage"></category></entry><entry><title>Bootstrapping an Ubuntu guest for Xen</title><link href="https://mikko.kortelainen.io/blog/bootstrapping-an-ubuntu-guest-for-xen/" rel="alternate"></link><published>2007-10-24T12:53:00+03:00</published><updated>2007-10-24T12:53:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-10-24:/blog/bootstrapping-an-ubuntu-guest-for-xen/</id><summary type="html">&lt;p&gt;First, some empty disk space is needed. Let's create a logical volume for our new virtual machine:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# lvcreate -n testlv -L 10G vg0
  Logical volume &amp;quot;testlv&amp;quot; created
&lt;/pre&gt;
&lt;p&gt;Create a filesystem on the new logical volume:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# mke2fs -j /dev/vg0/testlv
mke2fs 1.40-WIP (14-Nov-2006)
Filesystem label …&lt;/pre&gt;</summary><content type="html">&lt;p&gt;First, some empty disk space is needed. Let's create a logical volume for our new virtual machine:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# lvcreate -n testlv -L 10G vg0
  Logical volume &amp;quot;testlv&amp;quot; created
&lt;/pre&gt;
&lt;p&gt;Create a filesystem on the new logical volume:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# mke2fs -j /dev/vg0/testlv
mke2fs 1.40-WIP (14-Nov-2006)
Filesystem label=
OS type: Linux
Block size=4096 (log=2)
Fragment size=4096 (log=2)
1310720 inodes, 2621440 blocks
131072 blocks (5.00%) reserved for the super user
First data block=0
Maximum filesystem blocks=2684354560
80 block groups
32768 blocks per group, 32768 fragments per group
16384 inodes per group
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632

Writing inode tables: done
Creating journal (32768 blocks): done
Writing superblocks and filesystem accounting information: done

This filesystem will be automatically checked every 25 mounts or
180 days, whichever comes first.  Use tune2fs -c or -i to override.
&lt;/pre&gt;
&lt;p&gt;Create a mount point:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# mkdir /mnt/test
&lt;/pre&gt;
&lt;p&gt;Mount the new filesystem&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# mount /dev/vg0/testlv /mnt/test
&lt;/pre&gt;
&lt;p&gt;Bootstrap the new system. For this, we will use a utility called &amp;quot;debootstrap&amp;quot;, which can bootstrap a fresh Ubuntu installation easily:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# apt-get install debootstrap
root&amp;#64;xenserver1:~# debootstrap feisty /mnt/test
&lt;/pre&gt;
&lt;p&gt;After the system is bootstrapped, kernel modules must be copied inside the guest system for it to be able to load them during startup:modules:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# cp -a /lib/modules/2.6.19-4-server /mnt/test/lib/modules/
&lt;/pre&gt;
&lt;p&gt;Guest system's /etc/fstab must be created:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# nano -w /mnt/test/etc/fstab
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
proc            /proc           proc    defaults        0       0
/dev/sda1       /               ext3    defaults,errors=remount-ro 0       1
&lt;/pre&gt;
&lt;p&gt;Give the guest a hostname:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# echo &amp;quot;test&amp;quot; &amp;gt; /mnt/test/etc/hostname
&lt;/pre&gt;
&lt;p&gt;Umount the filesystem so that we can boot from it:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# umount /mnt/test/
&lt;/pre&gt;
&lt;p&gt;Create a Xen configuration file:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:/etc/xen/auto# nano -w /etc/xen/auto/test
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
kernel = &amp;quot;/boot/vmlinuz-2.6.19-4-server&amp;quot; # Your kernel image
ramdisk = &amp;quot;/boot/initrd.img-2.6.19-4-server&amp;quot; # The initial ramdisk
memory = 128 # Number of megabytes allocated
name = &amp;quot;test&amp;quot; # Virtual machine name
vcpus = 4 # Number of virtual CPUs the guest sees
vif = [ 'mac=aa:00:00:00:13:13, bridge=xenbr0' ] # A network interface
disk = [ 'phy:mapper/vg0-testlv,sda1,w' ] # The root disk
root = &amp;quot;/dev/sda1 ro&amp;quot; # Root partition the kernel mounts first
&lt;/pre&gt;
&lt;p&gt;Boot the machine:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;xenserver1:~# xm create -c /etc/xen/auto/test

Log in:

Ubuntu 7.04 test tty1

test login: root
&lt;/pre&gt;
&lt;p&gt;The root password is initially empty, which is not very secure. Change root password:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;test:~# passwd
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
&lt;/pre&gt;
&lt;p&gt;Configure network:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;test:~# vi /etc/network/interfaces
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
auto lo eth0
iface lo inet loopback
iface eth0 inet dhcp
&lt;/pre&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;test:~# /etc/init.d/networking restart
&lt;/pre&gt;
&lt;p&gt;Install some useful packages:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
root&amp;#64;test:~# apt-get update
root&amp;#64;test:~# apt-get install language-pack-fi
root&amp;#64;test:~# apt-get install nano cron bash man
root&amp;#64;test:~# apt-get install openssh-server
&lt;/pre&gt;
&lt;p&gt;That's it! You now have a working virtual machine ready for use.&lt;/p&gt;
</content><category term="Blog"></category><category term="Linux"></category><category term="Ubuntu"></category><category term="Virtualization"></category><category term="Xen"></category></entry><entry><title>How to get VMware Server working with an unsupported kernel and the vmware-any-any patch</title><link href="https://mikko.kortelainen.io/blog/how-to-get-vmware-server-working-with-an-unsupported-kernel-and-the-vmware-any-any-patch/" rel="alternate"></link><published>2007-10-17T20:23:00+03:00</published><updated>2007-10-17T20:23:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-10-17:/blog/how-to-get-vmware-server-working-with-an-unsupported-kernel-and-the-vmware-any-any-patch/</id><summary type="html">&lt;p&gt;VMware Server needs exactly two kernel modules running on the host system (there are separate modules for guest systems). These are the vmmon and the vmnet modules. Unfortunately, the vmmon and vmnet packages included in the VMware server distribution package don't compile with the newest kernels. When I upgraded my …&lt;/p&gt;</summary><content type="html">&lt;p&gt;VMware Server needs exactly two kernel modules running on the host system (there are separate modules for guest systems). These are the vmmon and the vmnet modules. Unfortunately, the vmmon and vmnet packages included in the VMware server distribution package don't compile with the newest kernels. When I upgraded my laptop to Gutsy Gibbon a few weeks ago, I forgot to check if VMware server supports the new kernel. And, of course, it doesn't yet. But luckily I found the vmware-any-any package, a patched version of the host kernel modules that works with newer kernel versions.&lt;/p&gt;
&lt;p&gt;You can download the package from here:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://knihovny.cvut.cz/ftp/pub/vmware/?M=D"&gt;http://knihovny.cvut.cz/ftp/pub/vmware/?M=D&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Download the &lt;a class="reference external" href="http://knihovny.cvut.cz/ftp/pub/vmware/vmware-any-any-update114.tar.gz"&gt;tarball&lt;/a&gt; and unpack it:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~/Desktop$ tar zxvf vmware-any-any-update114.tar.gz
vmware-any-any-update114/
vmware-any-any-update114/services.sh
vmware-any-any-update114/runme.pl
vmware-any-any-update114/update.c
vmware-any-any-update114/vmnet.tar
vmware-any-any-update114/update
vmware-any-any-update114/vmblock.tar
vmware-any-any-update114/vmmon.tar
&lt;/pre&gt;
&lt;p&gt;You also need the source code of your running kernel. On Ubuntu, you can get it by running:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~/Desktop$ sudo apt-get install linux-source
&lt;/pre&gt;
&lt;p&gt;There's a &amp;quot;runme.pl&amp;quot; script included which should be able to compile the modules and patch your system, but I couldn't get it working. Instead, I unpacked the the vmmon.tar and vmnet.tar and compiled them myself:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ tar xf vmmon.tar
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ tar xf vmnet.tar
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ cd vmmon-only
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114/vmmon-only$ make
.
.
.
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ cd ../vmnet-only
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114/vmnet-only$ make
.
.
.
&lt;/pre&gt;
&lt;p&gt;The result is two files which can be loaded into the kernel as modules: &lt;em&gt;vmmon.ko&lt;/em&gt; and &lt;em&gt;vmnet.ko&lt;/em&gt;. You can simply insert those into the kernel with the insmod command:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ sudo insmod vmnet-only/vmnet.ko
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ sudo insmod vmmon-only/vmmon.ko
&lt;/pre&gt;
&lt;p&gt;After that, VMware server starts up nicely!&lt;/p&gt;
&lt;p&gt;But one thing is still left. To be able to load the modules at startup properly, they must be copied to the kernel module tree under /lib. First I created a directory for the modules, and then copied them there. After that operation, the command &lt;em&gt;depmod&lt;/em&gt; must be run in order to create an up-to-date list of available modules:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ sudo mkdir /lib/modules/2.6.22-14-generic/vmware-server
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ sudo cp vmmon-only/vmmon.ko /lib/modules/2.6.22-14-generic/vmware-server/
mkortela&amp;#64;T60:~/Desktop/vmware-any-any-update114$ sudo cp vmnet-only/vmnet.ko /lib/modules/2.6.22-14-generic/vmware-server/
mkortela&amp;#64;T60:/lib/modules/2.6.22-12-generic/vmware-server$ sudo depmod
&lt;/pre&gt;
&lt;p&gt;That's it! Now you should be able to run VMware server, and all the modules should be loaded at runtime. Please note that if you are doing a fresh install of VMware server, you must now run the &lt;em&gt;vmware-config-network.pl&lt;/em&gt; script to configure the network.&lt;/p&gt;
&lt;p&gt;You can make sure that the modules load properly by unloading them with rmmod and then loading them again with modprobe:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:/lib/modules/2.6.22-12-generic/vmware-server$ sudo rmmod vmmon
mkortela&amp;#64;T60:/lib/modules/2.6.22-12-generic/vmware-server$ sudo rmmod vmnet
mkortela&amp;#64;T60:/lib/modules/2.6.22-12-generic/vmware-server$ sudo modprobe vmmon
mkortela&amp;#64;T60:/lib/modules/2.6.22-12-generic/vmware-server$ sudo modprobe vmnet
&lt;/pre&gt;
&lt;p&gt;Vmmon should print a status message like this in your dmesg:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
[  999.429124] /dev/vmmon[8602]: VMCI: Driver initialized.
[  999.432385] /dev/vmmon[8602]: Module vmmon: registered with major=10 minor=165
[  999.432756] /dev/vmmon[8602]: Module vmmon: initialized
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Ubuntu"></category><category term="VMware"></category></entry><entry><title>Updated version of the flash64.sh script for Ubuntu 7.10 Gutsy Gibbon</title><link href="https://mikko.kortelainen.io/blog/updated-version-of-the-flash64sh-script-for-ubuntu-710-gutsy-gibbon/" rel="alternate"></link><published>2007-10-02T06:28:00+03:00</published><updated>2007-10-02T06:28:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-10-02:/blog/updated-version-of-the-flash64sh-script-for-ubuntu-710-gutsy-gibbon/</id><summary type="html">&lt;p&gt;A few months ago I released a script to install a 32-bit Adobe Flash plugin to a 64-bit Firefox, but it doesn't seem to work in Gutsy beta. Here's an updated one. I upgraded my laptop to Gutsy and used this one to get Flash working.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Edit: I did a …&lt;/em&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;A few months ago I released a script to install a 32-bit Adobe Flash plugin to a 64-bit Firefox, but it doesn't seem to work in Gutsy beta. Here's an updated one. I upgraded my laptop to Gutsy and used this one to get Flash working.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Edit: I did a complete reinstall later and learned that Gutsy knows how to set this up by itself. So there's no need for this script anymore. And that is a very positive thing!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Just cut and paste it to &amp;quot;flash64.sh&amp;quot;, add execute permissions, and run it with sudo.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
#!/bin/sh

DEPS=&amp;quot;ia32-libs ia32-libs-gtk util-linux lib32asound2 alien&amp;quot;
GWENOLE=http://gwenole.beauchesne.info/projects/nspluginwrapper/files
PLUGIN=nspluginwrapper-0.9.91.4-1.x86_64.rpm
VIEWER=nspluginwrapper-i386-0.9.91.4-1.x86_64.rpm
MACROMEDIA=http://fpdownload.macromedia.com/get/flashplayer/current
FLASH=install_flash_player_9_linux.tar.gz

usage() {
  cat &amp;lt;&amp;lt; EOF
A script to install 32-bit Adobe Flash plugin in a 64-bit Firefox.
Usage: $0 [-k]
       -k   keep temporary files
EOF
}

while getopts &amp;quot;kh?&amp;quot; OPT
do
  case $OPT in
    &amp;quot;k&amp;quot;) KEEPTMP=1;;
    &amp;quot;h&amp;quot;|&amp;quot;?&amp;quot;|&amp;quot;help&amp;quot;) usage; exit;;
    *) echo Unrecognized option &amp;quot;$OPT&amp;quot;; usage; exit;;
  esac
done

if [ &amp;quot;`id -u`&amp;quot; != &amp;quot;0&amp;quot; ]
then
  echo You must be root in order to run this script.
  echo Try: &amp;quot;sudo $0&amp;quot; instead.
  echo For options and help, use &amp;quot;$0 -h&amp;quot;.
  exit 1
fi

TMP=`mktemp -d`
cd $TMP
echo Temporary directory $TMP created

echo Installing dependencies: $DEPS
apt-get -qq install $DEPS || exit 1

echo Getting nspluginwrapper plugin: $PLUGIN
wget -qc $GWENOLE/$PLUGIN

echo Getting nspluginwrapper viewer: $VIEWER
wget -qc $GWENOLE/$VIEWER

echo Installing plugin
alien -i $PLUGIN

echo Installing viewer
alien -i $VIEWER

echo Getting Flash plugin: $PLUGIN
wget -qc $MACROMEDIA/$FLASH

echo Installing Flash plugin to /usr/lib32/mozilla/plugins
mkdir -p /usr/lib32/mozilla/plugins
tar -Ozxf $FLASH install_flash_player_9_linux/flashplayer.xpt &amp;gt; /usr/lib32/mozilla/plugins/flashplayer.xpt
tar -Ozxf $FLASH install_flash_player_9_linux/libflashplayer.so &amp;gt; /usr/lib32/mozilla/plugins/libflashplayer.so

echo Creating a wrapper using nspluginwrapper
nspluginwrapper -i /usr/lib32/mozilla/plugins/libflashplayer.so

if [ &amp;quot;$KEEPTMP&amp;quot; = &amp;quot;1&amp;quot; ]
then
  echo Temporary files were left in: $TMP
else
  echo Removing temporary files
  rm -rf $TMP
fi

echo
echo The Flash plugin and wrapper have been installed.
echo You must restart Firefox.
&lt;/pre&gt;
</content><category term="Blog"></category><category term="Firefox"></category><category term="Shell scripts"></category><category term="Ubuntu"></category></entry><entry><title>Getting a Certificate for your Web Server</title><link href="https://mikko.kortelainen.io/blog/getting-a-certificate-for-your-web-server/" rel="alternate"></link><published>2007-10-01T21:50:00+03:00</published><updated>2007-10-01T21:50:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-10-01:/blog/getting-a-certificate-for-your-web-server/</id><summary type="html">&lt;p&gt;To communicate securely using &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Transport_Layer_Security"&gt;SSL (also known as TLS or Transport Layer Security)&lt;/a&gt;, web servers need a key pair of public and private keys. This key pair can be generated and signed by yourself, but to prevent the web browser from asking &amp;quot;stupid&amp;quot; questions about the validity of a certificate …&lt;/p&gt;</summary><content type="html">&lt;p&gt;To communicate securely using &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Transport_Layer_Security"&gt;SSL (also known as TLS or Transport Layer Security)&lt;/a&gt;, web servers need a key pair of public and private keys. This key pair can be generated and signed by yourself, but to prevent the web browser from asking &amp;quot;stupid&amp;quot; questions about the validity of a certificate, you must pay a company, called a &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Certificate_authority"&gt;Certificate authority&lt;/a&gt;, such as &lt;a class="reference external" href="http://www.verisign.com"&gt;Verisign&lt;/a&gt;, &lt;a class="reference external" href="http://www.geotrust.com/"&gt;Geotrust&lt;/a&gt;, or &lt;a class="reference external" href="http://www.thawte.com/"&gt;Thawte&lt;/a&gt;, for the added simplicity. That company will then verify that you are who you are (in theory, at least) and then sign your public key with their certificate. Their certificate is already bundled with most browsers and thus trusted by default, which also makes your newly signed certificate trusted as well.&lt;/p&gt;
&lt;p&gt;In short, the steps needed to get and install a key that is signed by a certification authority:&lt;/p&gt;
&lt;div class="line-block"&gt;
&lt;div class="line"&gt;1. Create an a public/private key pair&lt;/div&gt;
&lt;div class="line"&gt;2. Create a &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Certificate_signing_request"&gt;Certificate Signing Request&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;3. Submit your Certificate Signing Request to your &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Certificate_authority"&gt;Certificate Authority&lt;/a&gt;&lt;/div&gt;
&lt;div class="line"&gt;4. The CA will check your identity with a method they have chosen&lt;/div&gt;
&lt;div class="line"&gt;5. The CA will give back your certificate signed with theirs&lt;/div&gt;
&lt;div class="line"&gt;6. Copy the key file and the certificate file to your web server&lt;/div&gt;
&lt;div class="line"&gt;7. Configure your web server to use the new certificate&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="a-real-world-example"&gt;
&lt;h2&gt;A Real World Example&lt;/h2&gt;
&lt;p&gt;Now let's go through the steps given above with a real example. I have &lt;a class="reference external" href="http://www.openssl.org/"&gt;OpenSSL&lt;/a&gt;, and specifically the &lt;em&gt;openssl&lt;/em&gt; command line tool, installed on my machine, which is nice because it is one of the best tools available for handling SSL/TLS keys and certificates. If you are running a typical Linux installation, you will most likely have it installed already.&lt;/p&gt;
&lt;div class="section" id="create-a-public-private-key-pair"&gt;
&lt;h3&gt;1. Create a public/private key pair&lt;/h3&gt;
&lt;p&gt;The following command will create an RSA private key to the file specified, in this case &lt;em&gt;koo.fi.key&lt;/em&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~$ openssl genrsa 1024 &amp;gt; koo.fi.key
Generating RSA private key, 1024 bit long modulus
.....................................++++++
...++++++
e is 65537 (0x10001)
&lt;/pre&gt;
&lt;p&gt;Remember that this file contains private information which &lt;em&gt;must be kept very secret&lt;/em&gt;. In fact, after completing step 2, the only one who should have even read access to the file is the web server daemon.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="create-a-certificate-signing-request"&gt;
&lt;h3&gt;2. Create a Certificate Signing Request&lt;/h3&gt;
&lt;p&gt;Next we will use the openssl tool again to create the signing request, which will contain some information about us, as well as the public key of the key pair. This time OpenSSL will ask us some questions about the user of the certificate. This info should be as accurate as possible, but in most cases, it doesn't really matter what you write there. Usually the only field that has any meaning is the &amp;quot;Common Name&amp;quot; field, which should be the same as the domain name of your web server (&lt;em&gt;www.yourdomain.com&lt;/em&gt;). Here we will use the common name &lt;em&gt;koo.fi&lt;/em&gt;. The CSR will be output to the file &lt;em&gt;koo.fi.csr&lt;/em&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkortela&amp;#64;T60:~$ openssl req -new -key koo.fi.key -out koo.fi.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:FI
State or Province Name (full name) [Some-State]:Uusimaa
Locality Name (eg, city) []:Helsinki
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Techelp Oy
Organizational Unit Name (eg, section) []:
Common Name (eg, YOUR name) []:koo.fi
Email Address []:mikko.kortelainen&amp;#64;techelp.fi

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="submit-your-certificate-signing-request-to-your-certificate-authority"&gt;
&lt;h3&gt;3. Submit your Certificate Signing Request to your &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Certificate_authority"&gt;Certificate Authority&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now that we have one file for our private key and another one for the certificate signing request, it is time to pay a commercial CA a number of euros for signing our certificate.&lt;/p&gt;
&lt;p&gt;I have been using &lt;a class="reference external" href="http://www.rapidssl.com"&gt;RapidSSL.com&lt;/a&gt;, because they can provide me quite well accepted certificate quite cheaply and instantly. In fact, you don't even have to speak to any service personnel, because the authentication telephone call is automated.&lt;/p&gt;
&lt;p&gt;So click on the &amp;quot;BUY&amp;quot; button and answer all questions. When it is time to give the Certificate Signing Request, cut and paste the contents of your CSR file (_NOT_ the key file!).&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ca-will-check-your-identity-with-a-method-they-have-chosen"&gt;
&lt;h3&gt;4. The CA will check your identity with a method they have chosen&lt;/h3&gt;
&lt;p&gt;RapidSSL will give you and automated phone call. Follow instructions.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="the-ca-will-give-back-your-certificate-signed-with-theirs"&gt;
&lt;h3&gt;5. The CA will give back your certificate signed with theirs&lt;/h3&gt;
&lt;p&gt;In a couple of minutes you will get an e-mail containing the the certificate. Look for something like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
-----BEGIN CERTIFICATE-----
.
.
... a lot of gibberish ...
.
.
-----END CERTIFICATE-----
&lt;/pre&gt;
&lt;p&gt;Cut and paste that to a new file, mine was called &lt;em&gt;koo.fi.crt&lt;/em&gt;. This file now contains the signed certificate.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="copy-the-key-and-the-certificate-to-your-web-server"&gt;
&lt;h3&gt;6. Copy the key and the certificate to your web server&lt;/h3&gt;
&lt;p&gt;The last thing to do is to copy the key file and the signed certificate file (the one you got from your CA) to the web server in a location the web server will find them. I copied my certificate to:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/etc/ssl/koo.fi.crt
&lt;/pre&gt;
&lt;p&gt;And my private key to:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
/etc/ssl/private/koo.fi.key
&lt;/pre&gt;
&lt;p&gt;Then I changed the permissions like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
chown root:root /etc/ssl/koo.fi.crt
chown root:root /etc/ssl/private/koo.fi.key
chmod 644 /etc/ssl/koo.fi.crt
chmod 400 /etc/ssl/private/koo.fi.key
&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="section" id="configure-your-web-server-to-use-the-new-certificate"&gt;
&lt;h3&gt;7. Configure your web server to use the new certificate&lt;/h3&gt;
&lt;p&gt;The last step is, of course, to configure your web server to use the certificate. For Apache 2 you could add something like this to your configuration file:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
&amp;lt;Virtualhost *:443&amp;gt;
    ServerName koo.fi
    ServerAlias koo.fi
    DocumentRoot /path/to/documentroot
    ServerAdmin mikko&amp;#64;koo.fi

    SSLEngine on
    SSLCipherSuite ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
    SSLCertificateFile /etc/ssl/koo.fi.crt
    SSLCertificateKeyFile /etc/ssl/koo.fi.key
&amp;lt;/VirtualHost&amp;gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="section" id="what-next"&gt;
&lt;h2&gt;What next?&lt;/h2&gt;
&lt;p&gt;The next step is, of course, running your own Certification Authority. That is somewhat of an advanced topic, but perhaps you will see an article discussing it on this site later on.&lt;/p&gt;
&lt;p&gt;Before you go, though, you really should try the following commands on your key, signing request and certificate files:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
openssl rsa -noout -text -in koo.fi.key
openssl req -noout -text -in koo.fi.csr
openssl x509 -noout -text -in koo.fi.crt
&lt;/pre&gt;
&lt;p&gt;Those will give you a readable version of the contents. That can be really handy if you're in a hurry and forgot which file was which.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Apache"></category><category term="Cryptography"></category></entry><entry><title>Installing OpenSSH server on a Windows box</title><link href="https://mikko.kortelainen.io/blog/installing-openssh-server-on-a-windows-2003-server/" rel="alternate"></link><published>2007-08-21T13:35:00+03:00</published><updated>2007-08-21T13:35:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-08-21:/blog/installing-openssh-server-on-a-windows-2003-server/</id><summary type="html">&lt;p&gt;An SSH server can be handy on a Windows machine, too. Cygwin comes with OpenSSH, and provides a lot of useful tools which you can use over the SSH connection. Here's how to install Cygwin and OpenSSH server on a Windows machine.&lt;/p&gt;
&lt;p&gt;Install &lt;a class="reference external" href="http://www.cygwin.com"&gt;Cygwin&lt;/a&gt;. Make sure you also install OpenSSH …&lt;/p&gt;</summary><content type="html">&lt;p&gt;An SSH server can be handy on a Windows machine, too. Cygwin comes with OpenSSH, and provides a lot of useful tools which you can use over the SSH connection. Here's how to install Cygwin and OpenSSH server on a Windows machine.&lt;/p&gt;
&lt;p&gt;Install &lt;a class="reference external" href="http://www.cygwin.com"&gt;Cygwin&lt;/a&gt;. Make sure you also install OpenSSH under the Net category. You can download the installer from here:&lt;/p&gt;
&lt;p&gt;&lt;a class="reference external" href="http://www.cygwin.com/setup.exe"&gt;http://www.cygwin.com/setup.exe&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To successfully run OpenSSH on a Windows 2003 Server, you must create a new user account for it. This is because the SYSTEM account, which is the default when installing OpenSSH as a service, does not have the &amp;quot;Create a token object&amp;quot; right, which is needed for public key authentication. Luckily, the ssh-host-config command will create a user for you, if you wish. Just remember to select &amp;quot;yes&amp;quot; in the following prompts.&lt;/p&gt;
&lt;p&gt;In fact, two user accounts are created in the script below. The other one is for privilege separation, which will make your installation a bit more secure. There's no reason not to enable it.&lt;/p&gt;
&lt;p&gt;If you are installing OpenSSH on an Active Directory domain controller, the user accounts will be created in Active Directory. This is because a domain controller does not have a separate local user database, but the local user database is a copy of AD itself. Remember this if you are going to install OpenSSH on more than one DC. On the second installation, the user accounts are already created!&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
administrator&amp;#64;server ~
$ ssh-host-config
Generating /etc/ssh_host_key
Generating /etc/ssh_host_rsa_key
Generating /etc/ssh_host_dsa_key
Generating /etc/ssh_config file
Privilege separation is set to yes by default since OpenSSH 3.3.
However, this requires a non-privileged account called 'sshd'.
For more info on privilege separation read /usr/share/doc/openssh/README.privsep.

Should privilege separation be used? (yes/no) yes
Warning: The following function requires administrator privileges!
Should this script create a local user 'sshd' on this machine? (yes/no) yes
Generating /etc/sshd_config file

Warning: The following functions require administrator privileges!

Do you want to install sshd as service?
(Say &amp;quot;no&amp;quot; if it's already installed as service) (yes/no) yes

You appear to be running Windows 2003 Server or later.  On 2003 and
later systems, it's not possible to use the LocalSystem account
if sshd should allow passwordless logon (e. g. public key authentication).
If you want to enable that functionality, it's required to create a new
account 'sshd_server' with special privileges, which is then used to run
the sshd service under.

Should this script create a new local account 'sshd_server' which has
the required privileges? (yes/no) yes

Please enter a password for new user 'sshd_server'.  Please be sure that
this password matches the password rules given on your system.
Entering no password will exit the configuration.  PASSWORD=SECRET

User 'sshd_server' has been created with password 'SECRET'.
If you change the password, please keep in mind to change the password
for the sshd service, too.

Also keep in mind that the user sshd_server needs read permissions on all
users' .ssh/authorized_keys file to allow public key authentication for
these users!.  (Re-)running ssh-user-config for each user will set the
required permissions correctly.

Which value should the environment variable CYGWIN have when
sshd starts? It's recommended to set at least &amp;quot;ntsec&amp;quot; to be
able to change user context without password.
Default is &amp;quot;ntsec&amp;quot;.  CYGWIN=binmode ntsec tty

The service has been installed under sshd_server account.
To start the service, call `net start sshd' or `cygrunsrv -S sshd'.

Host configuration finished. Have fun!
&lt;/pre&gt;
&lt;p&gt;You should now have a new service, called &amp;quot;CYGWIN sshd&amp;quot;, installed. It doesn't start automatically, so you must start it either from the Windows Services MMC Console or from the command line with the command &amp;quot;net start sshd&amp;quot;.&lt;/p&gt;
</content><category term="Blog"></category><category term="OpenSSH"></category><category term="Windows"></category></entry><entry><title>Creating a RAID array out of cheap USB disks</title><link href="https://mikko.kortelainen.io/blog/creating-a-raid-array-out-of-cheap-usb-disks/" rel="alternate"></link><published>2007-08-05T15:33:00+03:00</published><updated>2007-08-05T15:33:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-08-05:/blog/creating-a-raid-array-out-of-cheap-usb-disks/</id><summary type="html">&lt;p&gt;A RAID array is a bunch of disks used together in co-operation to create a redundant storage facility. Hard drives are mechanical devices with moving parts, which makes them prone to failure. You can imagine what it means to spin the hard drive platters at 7200 rpm, for years without …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A RAID array is a bunch of disks used together in co-operation to create a redundant storage facility. Hard drives are mechanical devices with moving parts, which makes them prone to failure. You can imagine what it means to spin the hard drive platters at 7200 rpm, for years without a pause in a typical server setup. Eventually, all disks die. A disk may run for a decade without a hinge, but another disk of the same type may die after a year. The problem is, there is reliable way to predict when a particular disk dies.&lt;/p&gt;
&lt;p&gt;To fight this problem, a number of schemes have been devised. They collectively go by the name of RAID, or Redundant Array of Inexpensive disks. The common denominator for them is that they all use one or more extra disks to hold a second copy of the data, so that the failure of one disk will not interrupt service. An exception to this is RAID level 0, also known as striping, which really is no RAID at all, because it does not provide any kind of redundancy. As opposed to using the disks separately, striping will in fact increase the probability of a fatal disk crash. If one drive fails, the data on all drives will be lost. Striping is therefore useful only for temporary data storage.&lt;/p&gt;
&lt;p&gt;A failed disk should be replaced as soon as possible, because in a typical situation the array can not sustain another disk failure before a new disk has been added and the array rebuilt (with the notable exception of RAID 6). The good thing is, this all can be done without having to put the data offline.&lt;/p&gt;
&lt;p&gt;In this article I am going to show you how to create a RAID 5 array out of ordinary USB hard disk drives. Later on, I will show you how to extend the array with another disk to add some more space. The good thing about these drives is that they are cheap, and hot-pluggable. The result will obviously not be as fast as an array created out of SATA drives, but it serves well for storing your music, videos, backups etc. Running the command &amp;quot;hdparm -t&amp;quot; for my RAID array made out of SATA drives will give me a reading of about 68 MB/sec, as opposed to the USB array, which gets on average about 42 MB/sec. For many applications this is quite enough.&lt;/p&gt;
&lt;p&gt;By the way, the commands in this article apply to other kinds of drives as well. In fact, the USB hard disks show up as regular SCSI or SATA disks. You can create a RAID array from all kinds of block devices, and even mix them. You could, for example, create a RAID 1 out of two SATA disks, and then add one USB disk to the array as a spare.&lt;/p&gt;
&lt;div class="section" id="setting-up-the-array"&gt;
&lt;h2&gt;Setting up the array&lt;/h2&gt;
&lt;p&gt;That's enough theory, now it is time to get our hands dirty. In the beginning, my &lt;em&gt;/proc/partitions&lt;/em&gt; had lines like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
major minor  #blocks  name
   8    32  488386584 sdc
   8    48  488386584 sdd
   8    64  488386584 sde
   8    80  488386584 sdf
&lt;/pre&gt;
&lt;p&gt;Those were the four USB hard drives I wanted to use for my array.&lt;/p&gt;
&lt;p&gt;Before creating the array, the individual disks must be prepared. First, you must create a single primary partition on each disk, and set the partition type to &lt;em&gt;0xFD&lt;/em&gt; - &amp;quot;Linux RAID autodetect&amp;quot;. This way both you and the kernel will easily see that the partition belongs to a RAID array.&lt;/p&gt;
&lt;p&gt;Next, the command to create an array of three disks looks like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mdadm --create /dev/md0 --level=5 --raid-devices=3 /dev/sdc1 /dev/sdd1 /dev/sde1
&lt;/pre&gt;
&lt;p&gt;You should now have a device called &lt;em&gt;/dev/md0&lt;/em&gt;. That is the disk you are going to have to use from now on. To see the details of your newly created array, run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mdadm --detail /dev/md0
&lt;/pre&gt;
&lt;p&gt;The command will show you some basic information about your array, as well as status information for each of the disks. A RAID 5 array will continue to work even if at most one drive has failed. When a new, working drive is inserted into the array, it will take some time to copy the relevant data to the new drive. This will be shown as the &amp;quot;rebuild status&amp;quot; in the detailed listing. For example my 500GB USB hard drives take several hours to rebuild.&lt;/p&gt;
&lt;p&gt;You can get some interesting information also by looking at the file &lt;em&gt;/proc/mdstat&lt;/em&gt;. That file comes straight from the kernel, and contains some very basic info. For a rebuilding array, this file contains an estimate of the time left. Your new md device should also show up in &lt;em&gt;/proc/partitions&lt;/em&gt; now.&lt;/p&gt;
&lt;p&gt;To take advantage of our redundant array, a filesystem must be created on it. You can no more use the /dev/sdX devices directly, as that would corrupt the array. You must use the device /dev/md0 instead.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="logical-volume-management"&gt;
&lt;h2&gt;Logical Volume Management&lt;/h2&gt;
&lt;p&gt;If you want, you can create a filesystem directly on your md device, but I would recommend using &lt;a class="reference external" href="http://sourceware.org/lvm2/"&gt;LVM2&lt;/a&gt; instead. LVM stands for Logical Volume Manager, and it is quite a powerful tool for managing disks. To cut a long story short, it can be used to create, resize and move partitions very flexibly (on-line in almost every case), in addition to a number of other things.&lt;/p&gt;
&lt;p&gt;Make sure you have the LVM2 userland tools installed. For Ubuntu, &amp;quot;apt-get install lvm2&amp;quot;.&lt;/p&gt;
&lt;p&gt;First thing to do is create a &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Physical_volume"&gt;physical volume&lt;/a&gt; out of our new md device:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
pvcreate /dev/md0
&lt;/pre&gt;
&lt;p&gt;Step number two is to create a &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Volume_group"&gt;volume group&lt;/a&gt; which will act as a container for our logical volumes:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
vgcreate myvg /dev/md0
&lt;/pre&gt;
&lt;p&gt;myvg is just a name for our new volume group. You can use whatever name you want. It is used for distinguishing between volume groups, as there can be more than one in a given system.&lt;/p&gt;
&lt;p&gt;A volume group is just an abstraction used to group one or more physical volumes into a single space which can be divided into &lt;a class="reference external" href="http://en.wikipedia.org/wiki/Logical_volume"&gt;logical volumes&lt;/a&gt;. A logical volume looks just like a disk partition to the kernel, and so a filesystem can be created on it.&lt;/p&gt;
&lt;p&gt;Let's take a look first at our volume group. Running the command &lt;em&gt;vgs&lt;/em&gt; will give you a quick list of your volume groups:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
VG      #PV #LV #SN Attr   VSize   VFree
myvg      1   2   0 wz--n- 931,52G 931,52G
&lt;/pre&gt;
&lt;p&gt;As you see, you have now about 930 GB free space on your volume group. Next, let's create a 100 GB logical volume:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
lvcreate --size 100G --name mylv myvg
&lt;/pre&gt;
&lt;p&gt;The command &lt;em&gt;lvs&lt;/em&gt; will give a list of volumes in the system:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
LV       VG      Attr   LSize   Origin Snap%  Move Log Copy%
mylv     myvg    -wi-ao 100,00G
&lt;/pre&gt;
&lt;p&gt;The logical volume will now show up as the device &lt;em&gt;/dev/myvg/mylv&lt;/em&gt;. To create a file system on it:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mke2fs -j /dev/myvg/mylv
&lt;/pre&gt;
&lt;p&gt;You can now mount it anywhere you want. Let's create a mount point in &lt;em&gt;/myfs&lt;/em&gt; and mount the new logical volume there:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mkdir /myfs
mount /dev/myvg/mylv /myfs
&lt;/pre&gt;
&lt;p&gt;Add a line to &lt;em&gt;/etc/fstab&lt;/em&gt; to mount it automatically each boot.&lt;/p&gt;
&lt;p&gt;By the way, in addition to the commands &lt;em&gt;pvs&lt;/em&gt;, &lt;em&gt;vgs&lt;/em&gt; and &lt;em&gt;lvs&lt;/em&gt;, you can get more detailed information about the physical and logical volumes, and volume groups, with the commands &lt;em&gt;pvdisplay&lt;/em&gt;, &lt;em&gt;vgdisplay&lt;/em&gt; and &lt;em&gt;lvdisplay&lt;/em&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="extending-your-array"&gt;
&lt;h2&gt;Extending your array&lt;/h2&gt;
&lt;p&gt;The newest version of RAID support in the kernel includes support for extending a RAID 5 array. What that means is if you are running out of space, you can just plug in a new USB disk, extend the array, and then extend your filesystem. All this can be done with the filesystem online, and without ever rebooting your machine. Here's how.&lt;/p&gt;
&lt;p&gt;As you probably noticed, I intentionally left the fourth disk out of the array when first creating it. We will now add the fourth disk there.&lt;/p&gt;
&lt;p&gt;The growing process consists of two commands. The first command will add the new disk to the array, making it a spare drive, and the second one will grow the array to the new size:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mdadm /dev/md0 --add /dev/sdf1
mdadm --grow /dev/md0 --raid-disks 4
&lt;/pre&gt;
&lt;p&gt;You can now see with &amp;quot;mdadm -D /dev/md0&amp;quot; or &amp;quot;cat /proc/partitions&amp;quot; that the array is rebuilding. The reshape process will likely take several hours, and the new space will not be available before that:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
md0 : active raid5 sdf1[0] sdc1[3] sdd1[2] sde1[1]
      1465159488 blocks level 5, 64k chunk, algorithm 2 [4/4] [UUUU]
      [==================&amp;gt;..]  check = 94.3% (460724960/488386496) finish=39.1min speed=11763K/sec
&lt;/pre&gt;
&lt;p&gt;After the reshape is complete, you can add the new free space to the physical volume by running:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
pvresize /dev/md0
&lt;/pre&gt;
&lt;p&gt;Pvresize will by default resize the physical volume to fill all available space on the disk. And this is just what we want. &lt;em&gt;vgs&lt;/em&gt; will now show that we have more free disk space in myvg:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
VG      #PV #LV #SN Attr   VSize   VFree
myvg      1   2   0 wz--n- 1,36T   1,26T
&lt;/pre&gt;
&lt;p&gt;To add a terabyte to our logical volume:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
lvextend --size +1T /dev/myvg/mylv
&lt;/pre&gt;
&lt;p&gt;The last step is to increase the filesystem. A tool called ext2online can be used to extend the filesystem without umounting it. Install it with &amp;quot;apt-get install ext2resize&amp;quot;. Run the command like this:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
ext2online /dev/myvg/mylv
&lt;/pre&gt;
&lt;p&gt;And that's it. You have now added more free space to your filesystem without disrupting operation.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="detecting-problems-and-managing-failed-disks"&gt;
&lt;h2&gt;Detecting problems and managing failed disks&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;mdadm&lt;/em&gt; tool includes a monitor mode which can be used to monitor the array, detect problems and let you know about them. On an Ubuntu system, a configuration file exists in &lt;em&gt;/etc/mdadm/mdadm.conf&lt;/em&gt;. You can put your e-mail address on the &lt;em&gt;MAILADDR&lt;/em&gt; line to receive e-mail when &lt;em&gt;mdadm --monitor&lt;/em&gt; detects a problem. Just make sure your system can send e-mail properly.&lt;/p&gt;
&lt;p&gt;If a disk dies and you have set up a spare disk, the kernel will automatically rebuild the array using the spare. Otherwise the array will remain usable in a degraded state, but will not sustain another disk failure before you add more disks to it.&lt;/p&gt;
&lt;p&gt;You can remove the failed disk from the array with:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mdadm /dev/md0 --remove /dev/sdX
&lt;/pre&gt;
&lt;p&gt;To add another disk to the array, use:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mdadm /dev/md0 --add /dev/sdX
&lt;/pre&gt;
&lt;p&gt;If the array is missing a disk, the disk will automatically be used for rebuilding it. If the array is complete, the disk will be added as a spare.&lt;/p&gt;
&lt;p&gt;If you intentionally want to replace a drive with another one in a working array, run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;
mdadm /dev/md0 --add /dev/sdX --fail /dev/sdY --remove /dev/sdY
&lt;/pre&gt;
&lt;p&gt;This will add disk &lt;em&gt;/dev/sdX&lt;/em&gt; to the array and remove &lt;em&gt;/dev/sdY&lt;/em&gt; from it. Disk sdY must be marked as failed to be able to remove it.&lt;/p&gt;
&lt;/div&gt;
</content><category term="Blog"></category><category term="Storage"></category><category term="Ubuntu"></category></entry><entry><title>Installing the 32-bit Adobe Flash plugin on a 64-bit Firefox in Feisty</title><link href="https://mikko.kortelainen.io/blog/installing-the-32-bit-adobe-flash-plugin-on-a-64-bit-firefox-in-feisty/" rel="alternate"></link><published>2007-07-29T21:40:00+03:00</published><updated>2007-07-29T21:40:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-07-29:/blog/installing-the-32-bit-adobe-flash-plugin-on-a-64-bit-firefox-in-feisty/</id><summary type="html">&lt;p&gt;Here's a little script I made to make installing the 32-bit Flash plugin on a
64-bit Firefox easy. It was adapted from a script I found at the Ubuntu forums
(&lt;a class="reference external" href="http://ubuntuforums.org/showthread.php?t=425672"&gt;here&lt;/a&gt;), but since that did
not work right out of the box for me, I created one that does. The …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's a little script I made to make installing the 32-bit Flash plugin on a
64-bit Firefox easy. It was adapted from a script I found at the Ubuntu forums
(&lt;a class="reference external" href="http://ubuntuforums.org/showthread.php?t=425672"&gt;here&lt;/a&gt;), but since that did
not work right out of the box for me, I created one that does. The script uses
the &lt;a class="reference external" href="http://gwenole.beauchesne.info/en/projects/nspluginwrapper"&gt;nspluginwrapper&lt;/a&gt; tool by Gwenol&lt;/p&gt;
</content><category term="Blog"></category><category term="Firefox"></category><category term="Ubuntu"></category></entry><entry><title>Starting and stopping IBM Websphere MQ on a Redhat Enterprise Linux box</title><link href="https://mikko.kortelainen.io/blog/starting-and-stopping-ibm-websphere-mq-on-a-redhat-enterprise-linux-box/" rel="alternate"></link><published>2007-07-25T18:30:00+03:00</published><updated>2007-07-25T18:30:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-07-25:/blog/starting-and-stopping-ibm-websphere-mq-on-a-redhat-enterprise-linux-box/</id><summary type="html">&lt;p&gt;Here's a little script I made for starting and stopping Websphere MQ on a RHEL
4. It is useful for a simple configuration with one Queue Manager and listener.
Just put your queue manager name in the QMGR variable and the listener port to
the PORT variable, and save the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Here's a little script I made for starting and stopping Websphere MQ on a RHEL
4. It is useful for a simple configuration with one Queue Manager and listener.
Just put your queue manager name in the QMGR variable and the listener port to
the PORT variable, and save the script to your &lt;tt class="docutils literal"&gt;/etc/init.d&lt;/tt&gt;.&lt;/p&gt;
&lt;p&gt;Please understand that this script does not check if the processes actually stay
up or die as they should. But it is useful for automating the tasks during a
reboot.&lt;/p&gt;
&lt;p&gt;If you are looking for a more powerful administration tool for MQ, check out Dr.
Johannes B&lt;/p&gt;
</content><category term="Blog"></category><category term="Red Hat"></category><category term="Shell scripts"></category><category term="Websphere"></category></entry><entry><title>Site opened</title><link href="https://mikko.kortelainen.io/blog/moikka-maailma/" rel="alternate"></link><published>2007-07-24T22:03:00+03:00</published><updated>2007-07-24T22:03:00+03:00</updated><author><name>Mikko Kortelainen</name></author><id>tag:mikko.kortelainen.io,2007-07-24:/blog/moikka-maailma/</id><content type="html">&lt;p&gt;Welcome to Mikko's home page. There's nothing much here quite yet, but I'm working on it.&lt;/p&gt;
</content><category term="Blog"></category><category term="Site info"></category></entry></feed>