Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background:[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

.viewer table, table.twtable {border:2px solid [[ColorPalette::TertiaryDark]];}
.viewer th, .viewer thead td, .twtable th, .twtable thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
.viewer td, .viewer tr, .twtable td, .twtable tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0em 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0em;}
.wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em 0.1em 0.2em;}

#messageArea {position:fixed; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0em 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0em 1em;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0em 0.25em; padding:0em 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0em; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which use a logographic writing system and need larger font sizes.
***/

/*{{{*/
body {font-size:0.8em;}

#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}

.subtitle {font-size:0.8em;}

.viewer table.listView {font-size:0.95em;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='tiddlerDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

Your username for signing your edits. Write it as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see AdvancedOptions
In /etc/bind/named.conf, add:
{{{
zone "tld." {
        type slave;
        file "tld";
        masters {
               192.168.181.19;
        };
};

zone "168.192.in-addr.arpa."{
   type slave ;
   file "192.168";
   masters {
       192.168.181.19;
   };
};
}}}
# cmd muninpks pokersource.info muninpks.pokersource.mksp.tld loic@dachary.org
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance/vserver_master/vserver -v ../@realm < <(dog --no-header $meta))"
view_host=$name.$realm.$vserver_realm.tld
name="$1"
domain="$2"
host="$3"
author="$4"
cd /etc/bind

test -f views/$domain.view

if ! grep "^$name" views/$domain.view > /dev/null
then
    echo -e "$name\t\tIN\tCNAME\t$host." >> views/$domain.view
    /etc/init.d/bind9 reload
    hg commit -u $author -m "bind $name to $host in $domain view" /etc/bind
fi
#
* ''Apache appliance on a laptop inside a LAN''
** Proppy wants to run a new online service available to the general public.
** Proppy creates a bridge on his GNU/Linux laptop and name it br0
** The br0 interface is assigned a permanent private IP address in the range 192.168.50.0/24.
**  Proppy adds shorewall rules to NAT all outgoing packets from br0 and route them to eth0 or wlan0 (the wifi interface).
** The 37000:38000 port range is DNAT to br0.
** Proppy creates a new Debian lenny based kvm with address 192.168.50.10 on br0 and names it VOD.
** Apache2 is installed in VOD and bound to 37080 in addtion to the 80 port.
** The laptop is run from inside a ~NATed LAN and and has a fixed DHCP allocated fixed IP based on his MAC address.
** Proppy adds a rule to the firewall ~NATing the LAN so that ports 37000:38000 are redirected to the laptop fixed IP.
# cmd openalpp osgal dachary.org
set -e

name="$1"
newname="$2"
domain="$3"

cd /etc/apache2
a2dissite $name.$domain
mv sites-available/$name.$domain sites-available/$newname.$domain
perl -pi -e "s/\b$name\b/$newname/g" sites-available/$newname.$domain
! grep -l $name sites-available/$newname.$domain
a2ensite $newname.$domain
for log in /var/log/apache2/*$name* ; do
    newlog=$(echo $log | perl -p -e "s/\b$name\b/$newname/g")
    mv $log $newlog
done
/etc/init.d/apache2 reload
* Request for inclusion in debian package http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=425008;repeatmerged=no

* One liner that will work on a newly installed apache2 from Debian GNU/Linux etch
{{{
author=loic@dachary.org ; app=apache2 ; apt-get install -y --force-yes $app && hg addremove && hg commit -u $author -m "apt-get install $app"
app=patch ; apt-get install -y --force-yes $app && hg addremove && hg commit -u $author -m "apt-get install $app"
cd / ; wget -O - http://hg.nagios.fsffrance.org/raw-rev/22ed4d555572 | patch -p1 
hg commit -m 'Apache x-forwarded-for log when behind a proxy' /etc/apache2
/etc/init.d/apache2 reload
}}}
* Emacs macro
{{{
; C-x e on the CustomLog line
(setq last-kbd-macro "\C-k\C-k\C-y\C-y\C-p\C-p\C-e env=!from_proxy\C-n_forwarded env=from_proxy")
}}}
* Complete patch
{{{
cd /
patch -p1 <<'EOF'
--- a/etc/apache2/apache2.conf	Thu May 03 23:57:15 2007 +0200
+++ b/etc/apache2/apache2.conf	Thu May 03 23:59:07 2007 +0200
@@ -199,9 +199,12 @@ Include /etc/apache2/conf.d/
 # a CustomLog directive (see below).
 #
 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_forwarded
 LogFormat "%h %l %u %t \"%r\" %>s %b" common
 LogFormat "%{Referer}i -> %U" referer
 LogFormat "%{User-agent}i" agent
+
+SetEnvIfNoCase X-Forwarded-For "." from_proxy=1
 
 #
 # ServerTokens
--- a/etc/apache2/sites-available/default	Thu May 03 23:57:15 2007 +0200
+++ b/etc/apache2/sites-available/default	Thu May 03 23:59:07 2007 +0200
@@ -34,7 +34,8 @@ NameVirtualHost *
 	# alert, emerg.
 	LogLevel warn
 
-	CustomLog /var/log/apache2/access.log combined
+	CustomLog /var/log/apache2/access.log combined env=!from_proxy
+	CustomLog /var/log/apache2/access.log combined_forwarded env=from_proxy
 	ServerSignature On
 
EOF
}}}
{{{
diff -r 36c2ae3235c9ea8a3d640b6dba5811ed6a54f9f0 -r b03e45844f4ee52e777288dad5c2cf3a361f92bd bind/db.aminche.com
--- a/bind/db.aminche.com	Mon Apr 02 00:16:32 2007 +0200
+++ b/bind/db.aminche.com	Thu May 17 21:32:08 2007 +0200
@@ -1,6 +1,6 @@
 $ttl 3d
 @       IN      SOA     ns.aminche.com. hostmaster.aminche.com. (
-                        2007040102      ; serial, todays date + todays serial #
+                        2007041602      ; serial, todays date + todays serial #
                         28800           ; refresh, seconds
                         7200            ; retry, seconds
                         604800          ; expire, seconds
@@ -28,4 +28,5 @@ muzine		IN	A 88.191.13.165
 muzine		IN	A 88.191.13.165
 hg		IN	A 88.191.13.165
 zanna		IN	A 88.191.13.165
+*.aminche.com.	IN	A 88.191.13.165
 aminche.com.	IN	A 88.191.13.165

}}}
** Proppy boots the real machine using a live CD
** Proppy installs and run the ssh daemon
** The ssh daemon allows root access and the password is set
** The hard disk is explored using fdisk
** Proppy mounts the file systems in /mnt as if it was / (for instance /dev/sda2 on /mnt and /dev/sda3 on /mnt/home)
** From the vserver host, proppy copies all the files (could also be done using the rsync vserver build method but it would not cross the file system boundaries because of the -x option and would therefore miss files)
{{{
rsync -avH --numeric-ids root@mekensleep.com:/mnt/ /var/lib/vservers/newmachine/
}}}
mkdir app
cd app
mkdir universe
ruby /usr/bin/tiddlywiki_cp -a http://garden.dachary.org/universe.html universe
emacs meta.xml # use model http://yocto-reader.flouzo.net/meta/meta.xml

meta=http://localhost/app/meta.xml

script_url="$(xmlstarlet sel -t -v /appliance/public_ns/@create < <(dog --no-header "$meta"))" ; \
 ssh -p $(xmlstarlet sel -t -v /appliance/public_ns/@ns_port < <(dog --no-header "$meta")) \
        root@$(xmlstarlet sel -t -v /appliance/public_ns/@public_ns < <(dog --no-header "$meta")) \
        bash -x '<(dog --no-header '$script_url')' $meta

script_url="$(xmlstarlet sel -t -v /appliance//ns/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance/vm_master/ns -v ../@host < <(dog --no-header "$meta")) \
        bash -x '<(dog --no-header '$script_url')' $meta

script_url="$(xmlstarlet sel -t -v /appliance//vm/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance/vm_master/vserver -v ../@host < <(dog --no-header "$meta")) \
        bash -x '<(dog --no-header '$script_url')' $meta

script_url="$(xmlstarlet sel -t -v /appliance//garden/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//garden -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| ssh $(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header "$meta")) bash -x -s '$meta'

script_url="$(xmlstarlet sel -t -v /appliance//mercurial/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//mercurial -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| ssh $(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header "$meta")) bash -x -s '$meta'

script_url="$(xmlstarlet sel -t -v /appliance//http_proxy/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//http_proxy -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| ssh $(xmlstarlet sel -t -v /appliance//http_proxy/@vserver_name < <(dog --no-header "$meta")) bash -x -s '$meta'


script_url="$(xmlstarlet sel -t -v /appliance//nagios/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -m /appliance//nagios -v ../@host < <(dog --no-header "$meta")) \
   cat '<(dog --no-header '$script_url')' \| vserver $(xmlstarlet sel -t -v /appliance//nagios/@vserver_name < <(dog --no-header "$meta")) exec "bash -x -s '$meta'"

nagios_vserver_host=mango.pokersource.info
nagios_name=nagiosfsf
parent_in_nagios_graph=mango
#nagios_host=hg.$name.$realm.$vserver_realm.tld.
nagios_host=hg.$name.$domain.
scp universe/Monitor\ the\ mercurial\ server\ with\ nagios.tiddler root@$nagios_vserver_host:/var/lib/vservers/$nagios_name/tmp/step7
ssh root@$nagios_vserver_host vserver $nagios_name exec "bash -x /tmp/step7 hg.$name $domain $parent_in_nagios_graph $nagios_host $author"

script_url="$(xmlstarlet sel -t -v /appliance/rss/@create < <(dog --no-header "$meta"))" ; \
 ssh root@$(xmlstarlet sel -t -v /appliance/rss/@host < <(dog --no-header $meta)) bash -x '<(dog --no-header '$script_url')' $meta

rss_host=dachary.org
#rss_url=http://hg.$name.$domain/rss-log
rss_url=http://$name.conf.tld:8000/rss-log
scp universe/Syndicate\ the\ mercurial\ changes.tiddler root@$rss_host:/tmp/step8
ssh root@$rss_host bash -x /tmp/step8 $rss_url $name

service=ssh
zone=tld
scp 'universe/open firewall port for appliance.tiddler' root@$vserver_host:/tmp/step9
ssh -t root@$vserver_host bash -x /tmp/step9 $name $domain $service $realm $vserver_realm $zone
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance/vserver_master/vserver -v ../@realm < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
vserver_name="$name.$realm.$vserver_realm.tld"
apt-get install debootstrap util-vserver
ip=$(getent hosts $vserver_name | cut -f1 -d' ')
test "$ip"
fqdn=$name.$domain
method="$(xmlstarlet sel -t -v /appliance/vserver_master/vserver/@distribution < <(dog --no-header $meta))"
case "$method" in
etch|lenny)
        method="debootstrap -- -d $method -m http://ftp.fr.debian.org/debian "
        ;;
skeleton)
        method=skeleton
        ;;
esac
iface=$(xmlstarlet sel -t -m /appliance/vserver_master/vserver -v ../@iface < <(dog --no-header $meta))
#ip=$(getent hosts $name.$domain | head -1 | cut -f1 -d' ')
addr=$(expr $ip : '.*\.\([0-9]*\)')
test "$addr"
net=$(expr $ip : '\(.*\)\.')
test "$net"
eval vserver $name build --hostname $fqdn --interface a$addr=$iface:$net.$addr/24 --context 2$addr -m $method
echo default > /etc/vservers/$name/apps/init/mark
hg addremove /etc/vservers
hg commit -u $author -m "create $name vserver" /etc/vservers
cat > /var/lib/vservers/$name/etc/resolv.conf <<EOF
search $domain
nameserver $net.1
EOF
case "$method" in
etch|lenny)
        if ! grep APT::Cache-Limit /etc/apt/apt.conf.d/70debconf > /dev/null ; then
		echo 'APT::Cache-Limit 100000000;' >> /etc/apt/apt.conf.d/70debconf
	fi
        ;;
esac
mkdir -p /var/lib/vservers/$name/proc /var/lib/vservers/$name/sys
if ! test -h /var/lib/vservers/$name/dev/fd ; then
  ln -s /proc/self/fd /var/lib/vservers/$name/dev/fd
fi
chroot /var/lib/vservers/$name apt-get remove --yes klogd || /bin/true
chroot /var/lib/vservers/$name update-rc.d cron defaults
env -i TERM=vt100 /usr/sbin/vserver $name start
echo DONE
* one DHCP server per LAN
* configuration under mercurial
* share configuration with NFS
should be converted to use the programable API of bind9 at some point
* The named.conf file //must// include views only. That's the only tricky bit : the top level configuration file may not contain any stanza. When views are used, all must be views. Note that match-clients is on the same line as {{{view}}} so that scripts can easily manipulate it.
{{{
include "/etc/bind/named.conf.options";

view "pokersource.info" { match-clients { 192.168.50.10; };
  zone "conf.tld" {
    type master;
    file "/etc/bind/pokersource.info.view";
  };
  include "/etc/bind/named.conf.zones";
  include "/etc/bind/named.conf.common";
};

view "default" {
  include "/etc/bind/named.conf.zones";
  include "/etc/bind/named.conf.common";
};

include "/etc/bind/named.conf.local";

}}}

* The //named.conf.common// that's included in each view holds what you'd like to include outside the views if bind9 allowed this. It's typically what you find in a named.conf bind9 file when not using views:

{{{
// prime the server with knowledge of the root servers
zone "." {
	type hint;
	file "/etc/bind/db.root";
};

// be authoritative for the localhost forward and reverse zones, and for
// broadcast zones as per RFC 1912

zone "localhost" {
	type master;
	file "/etc/bind/db.local";
};

zone "127.in-addr.arpa" {
	type master;
	file "/etc/bind/db.127";
};

zone "0.in-addr.arpa" {
	type master;
	file "/etc/bind/db.0";
};

zone "255.in-addr.arpa" {
	type master;
	file "/etc/bind/db.255";
};
}}}

* The {{{/etc/bind/named.conf.zones}}} file included in the {{{/etc/bind/named.conf}}} contains the list of supported zones (master, slave and forwarded). Forwarded zones are used to make sure DNS requests for domains under your control refer only to the master server, to [[avoid propagation delays|avoid DNS delays]]. 
{{{
zone "my" {
	type master;
	file "/etc/bind/db.my";
};

zone "pokersource.info."{
   type forward ;
   forward only ;
   forwarders {
       88.191.250.41 ;
   } ;
};
}}}
In the above file, the //my// zone is used to define the .my top level domain that points to the IP of the appliances running on the local machine and unknown to the outside world.
# cmd meta
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
cname="$(xmlstarlet sel -t -v /appliance/public_ns/@cname < <(dog --no-header $meta))"
dns="$(xmlstarlet sel -t -v /appliance/public_ns/@public_ns_ip < <(dog --no-header $meta))"
cd /etc/bind
if ! grep $domain db.$domain > /dev/null
then
    echo "the /etc/bind/db.$domain file must exist and contain the $domain string"
    exit 1
fi
if ! grep "^$name" db.$domain > /dev/null
then
    echo "$name                IN      CNAME   $cname." >> db.$domain
    echo "hg.$name             IN      CNAME   $cname." >> db.$domain
    perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' db.$domain
    /etc/init.d/bind9 reload
    sleep 2
fi
dig @$dns $name.$domain | grep "CNAME.*$cname"
dig @$dns hg.$name.$domain | grep "CNAME.*$cname"
hg commit -u $author -m "define $name.$domain" /etc/bind/db.$domain
echo DONE
# cmd markerclock 192.168.50 call dachary dachary.org loic@dachary.org
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
net="$(xmlstarlet sel -t -m /appliance//ns -v ../@net < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance//ns -v ../@realm < <(dog --no-header $meta))"
reverse=$(echo $net | perl -p -e 's/(\d+).(\d+).(\d+)/$3.$2.$1/')
cd /etc/bind
db_file=db.$net
if ! test -f $db_file
then
        db_file=db.$(expr $net : '\(.*\)\.')
fi

if ! dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld.*IN.*A" > /dev/null
then
        perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' \
                $db_file db.$vserver_realm views/$domain.view
        ip=$(expr "$(grep available $db_file | tail -1)" : '.*available-\([0-9][0-9]*\)')
        if test -z "$ip"
        then
                echo "NO IP"
                exit 1
        fi
        for file in $db_file db.$vserver_realm
        do
                if ! grep "^$name.$realm" $file > /dev/null
                then
                        perl -pi -e "s/available-$ip/$name.$realm/" $file
                fi
        done
	vserver_proxy="$(xmlstarlet sel -t -m /appliance//http_proxy -v ../@host < <(dog --no-header $meta))"
	domain_proxy="$(xmlstarlet sel -t -m /appliance//http_proxy/@domain < <(dog --no-header $meta))"
	vserver_ns="$(xmlstarlet sel -t -m /appliance//ns -v ../@host < <(dog --no-header $meta))"
	if [ "$domain_proxy" -a "$vserver_proxy" = "$vserver_ns" -a "$domain" != "$domain_proxy" ] ; then
	        if ! grep "^$name" views/$domain_proxy.view > /dev/null
	        then
	                echo -e "$name\t\tIN\tCNAME\t$name.$realm.$vserver_realm.tld." >> views/$domain_proxy.view
	        fi
	fi
        if ! grep "^$name" views/$domain.view > /dev/null
        then
                echo -e "$name\t\tIN\tCNAME\t$name.$realm.$vserver_realm.tld." >> views/$domain.view
        fi
        /etc/init.d/bind9 reload
        sleep 2
        dig @$net.1 $name.$realm.$vserver_realm.tld. | grep $ip
        dig @$net.1 -x $net.$ip | grep $name.$realm.$vserver_realm.tld
else
        ip=$(expr "$(dig @$net.1 $name.$realm.$vserver_realm.tld | grep \^$name.$realm)" : ".*$net.\([0-9]*\)")
fi
# ??? how to test that a resolution within a view works ???
perl -pi -e 's/};$/'$net.$ip'; };/ if(/^view "'$realm'/ && !/'$net.$ip'/)' named.conf
grep "$realm.*$net.$ip" named.conf
/etc/init.d/bind9 reload
hg commit -u $author -m "define $name local names in $realm" /etc/bind
echo DONE
pecho:~# meta=http://garden.conf.tld/packaging-farm.xml

pecho:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
realm="$(xmlstarlet sel -t -v /appliance/@realm < <(dog --no-header $meta))"
net="$(xmlstarlet sel -t -m /appliance//ns -v ../@net < <(dog --no-header $meta))"
vserver_realm="$(xmlstarlet sel -t -m /appliance//ns -v ../@realm < <(dog --no-header $meta))"
pecho:~# pecho:~# pecho:~# pecho:~# pecho:~# pecho:~# 
pecho:~# echo $realm
dachary
pecho:~# cd /etc/bind
pecho:/etc/bind# reverse=$(echo $net | perl -p -e 's/(\d+).(\d+).(\d+)/$3.$2.$1/')
pecho:/etc/bind# db_file=db.$net
if ! test -f $db_file
then
        db_file=db.$(expr $net : '\(.*\)\.')
fi
pecho:/etc/bind# > > > pecho:/etc/bind# 
pecho:/etc/bind# echo $db_file
db.192.168
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld | grep "^$name.$realm.$vserver_realm.tld.*IN.*A"
pecho:/etc/bind# echo dig @$net.1 $name.$realm.$vserver_realm.tld
dig @192.168.50.1 packaging-farm.dachary.fsf.tld
pecho:/etc/bind# ifconfig
*** output flushed ***
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld.*IN.*A"
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. 

; <<>> DiG 9.3.2-P1 <<>> @192.168.50.1 packaging-farm.dachary.fsf.tld.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 23377
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0

;; QUESTION SECTION:
;packaging-farm.dachary.fsf.tld.	IN	A

;; AUTHORITY SECTION:
fsf.tld.		1800	IN	SOA	ns.fsf.tld. hostmaster.fsf.tld. 2007072308 3600 1800 1209600 1800

;; Query time: 0 msec
;; SERVER: 192.168.50.1#53(192.168.50.1)
;; WHEN: Thu Sep 27 00:06:12 2007
;; MSG SIZE  rcvd: 98

pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. 

; <<>> DiG 9.3.2-P1 <<>> @192.168.50.1 packaging-farm.dachary.fsf.tld.
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 12598
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 1

;; QUESTION SECTION:
;packaging-farm.dachary.fsf.tld.	IN	A

;; ANSWER SECTION:
packaging-farm.dachary.fsf.tld.	3600 IN	A	192.168.50.20

;; AUTHORITY SECTION:
fsf.tld.		3600	IN	NS	ns.fsf.tld.

;; ADDITIONAL SECTION:
ns.fsf.tld.		3600	IN	A	192.168.50.1

;; Query time: 0 msec
;; SERVER: 192.168.50.1#53(192.168.50.1)
;; WHEN: Thu Sep 27 00:09:55 2007
;; MSG SIZE  rcvd: 97

pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld.*IN.*A"
packaging-farm.dachary.fsf.tld.	3600 IN	A	192.168.50.20
pecho:/etc/bind#        perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' \
                $db_file db.$vserver_realm views/$domain.view
> pecho:/etc/bind# 
pecho:/etc/bind# hg diff .
diff -r b01accd3be91 etc/bind/db.192.168
--- a/etc/bind/db.192.168	Thu Sep 27 00:09:42 2007 +0200
+++ b/etc/bind/db.192.168	Thu Sep 27 00:11:01 2007 +0200
@@ -4,7 +4,7 @@
 ;
 $TTL	604800
 @	IN	SOA	localhost. root.localhost. (
-			2007092700	; serial
+			2007092701	; serial
 			 604800		; Refresh
 			  86400		; Retry
 			2419200		; Expire
diff -r b01accd3be91 etc/bind/db.fsf
--- a/etc/bind/db.fsf	Thu Sep 27 00:09:42 2007 +0200
+++ b/etc/bind/db.fsf	Thu Sep 27 00:11:01 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN fsf.tld.
 @                       IN      SOA             ns hostmaster (
-			2007092700	; serial
+			2007092701	; serial
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
diff -r b01accd3be91 etc/bind/views/dachary.org.view
--- a/etc/bind/views/dachary.org.view	Thu Sep 27 00:09:42 2007 +0200
+++ b/etc/bind/views/dachary.org.view	Thu Sep 27 00:11:01 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN conf.tld.
 @                       IN      SOA             ns hostmaster (
-			2007092700	; serial
+			2007092701	; serial
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
pecho:/etc/bind# echo $db_file
db.192.168
pecho:/etc/bind# grep $name $db_file
20.50	IN	PTR	packaging-farm.dachary.fsf.tld.
pecho:/etc/bind# getent hosts $name.$realm.$vserver_realm.tld.
192.168.50.20   packaging-farm.dachary.fsf.tld
pecho:/etc/bind# expr "$(getent hosts $name.$realm.$vserver_realm.tld.)" : ".*\.\([0-9][0-9]*\)"
20
pecho:/etc/bind# ip=(expr "$(getent hosts $name.$realm.$vserver_realm.tld.)" : ".*\.\([0-9][0-9]*\)")
pecho:/etc/bind# echo $ip
expr
pecho:/etc/bind# ip=$(expr "$(getent hosts $name.$realm.$vserver_realm.tld.)" : ".*\.\([0-9][0-9]*\)")
pecho:/etc/bind# echo $ip
20
pecho:/etc/bind# perl -pi -e "s/$name.$realm/available-$ip/" $db_file
pecho:/etc/bind# perl -pi -e "s/$name.$realm/available-$ip/" db.$vserver_realm
pecho:/etc/bind# perl -pi -e '$_ = "" if(/^'$name'/)' views/$domain.view
pecho:/etc/bind# /etc/init.d/bind9 reload
Reloading domain name service...: bind.
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep $ip
fsf.tld.		1800	IN	SOA	ns.fsf.tld. hostmaster.fsf.tld. 2007092702 3600 1800 1209600 1800
;; WHEN: Thu Sep 27 00:34:10 2007
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep $name.$realm.$vserver_realm.tld
; <<>> DiG 9.3.2-P1 <<>> @192.168.50.1 packaging-farm.dachary.fsf.tld.
;packaging-farm.dachary.fsf.tld.	IN	A
pecho:/etc/bind# dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld"
pecho:/etc/bind# ! dig @$net.1 $name.$realm.$vserver_realm.tld. | grep "^$name.$realm.$vserver_realm.tld"
pecho:/etc/bind# echo $net.$ip
192.168.50.20
pecho:/etc/bind# grep $net.$ip named.conf
view "dachary.org" { match-clients { 192.168.50.13; 192.168.50.14; 192.168.50.17; 192.168.50.19; 192.168.50.20; 192.168.50.22; 192.168.50.23; 192.168.50.27; 192.168.50.28; 192.168.50.33; 192.168.50.35; 192.168.50.38; 192.168.50.40; 192.168.50.41; 192.168.50.43; 192.168.50.44; 88.191.250.36; 192.168.50.254; 192.168.50.253; 192.168.50.251; 192.168.50.250; 192.168.50.249; 192.168.50.248; };
pecho:/etc/bind# perl -pi -e "s/$net.$ip; //" named.conf
pecho:/etc/bind# hg status .
M db.192.168
M db.fsf
M named.conf
M views/dachary.org.view
pecho:/etc/bind# grep $net.$ip named.conf
pecho:/etc/bind# /etc/init.d/bind9 reload
Reloading domain name service...: bind.
pecho:/etc/bind# hg commit -u $author -m "undefine $name local names in $realm" /etc/bind
pecho:/etc/bind# echo DONE
DONE
pecho:/etc/bind# 
ns2:~# meta=http://garden.conf.tld/packaging-farm.xml
ns2:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
ns2:~# author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
ns2:~# domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
ns2:~#
ns2:~# cd /etc/bind
ns2:/etc/bind# echo $domain
dachary.org
ns2:/etc/bind# #perl -pi -e '$_ = '' if(/^'$name'/ || /^hg.'$name'/)' db.$domain
ns2:/etc/bind# grep $name db.$domain
packaging-farm          IN      CNAME   dachary.org.
hg.packaging-farm       IN      CNAME   dachary.org.
ns2:/etc/bind# perl -pi -e '$_ = '' if(/^'$name'/ || /^hg.'$name'/)' db.$domain
syntax error at -e line 1, near "=  if"
Execution of -e aborted due to compilation errors.
ns2:/etc/bind# perl -pi -e '$_ = "" if(/^'$name'/ || /^hg.'$name'/)' db.$domain
ns2:/etc/bind# grep $name db.$domain
ns2:/etc/bind# dns="$(xmlstarlet sel -t -v /appliance/public_ns/@public_ns_ip < <(dog --no-header $meta))"
ns2:/etc/bind# echo $dns
192.168.50.16
ns2:/etc/bind#     perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' db.$domain
ns2:/etc/bind# hg diff db.$domain
*** output flushed ***
ns2:/etc/bind# /etc/init.d/bind9 reload
Reloading domain name service...: bind.
ns2:/etc/bind#
ns2:/etc/bind# ! dig @$dns $name.$domain | grep "CNAME.*$cname"
ns2:/etc/bind# #hg commit -u $author -m "undefine $name.$domain" /etc/bind/db.$domain
ns2:/etc/bind# echo $author
loic@dachary.org
ns2:/etc/bind# hg commit -u $author -m "undefine $name.$domain" /etc/bind/db.$domain
ns2:/etc/bind#
* each VM has a LVM volume
* the LVM volume is DRBD copied on another hardware over WAN
[[Summary]]
[[Rationale]]
[[Use Cases]]
[[Scope]]
[[Design]]
[[Implementation]]
[[Unresolved Issues]]
set -e
meta="$1"
echo $meta
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
echo $name
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
http_host="$(xmlstarlet sel -t -v /appliance//http_proxy/@http_host < <(dog --no-header $meta))"
hg_host="$(xmlstarlet sel -t -v /appliance//http_proxy/@hg_host < <(dog --no-header $meta))"
cd /etc/apache2/mods-available/
if ! a2enmod proxy_http | grep already ; then
patch <<'EOF'
diff -r 8177988b2d1d etc/apache2/mods-available/proxy.conf
--- a/etc/apache2/mods-available/proxy.conf     Fri Mar 30 12:18:19 2007 +0200
+++ b/etc/apache2/mods-available/proxy.conf     Fri Aug 03 18:40:24 2007 +0200
@@ -7,7 +7,8 @@

        <Proxy *>
                Order deny,allow
-               Deny from all
+               Allow from all
+               #Deny from all
                #Allow from .your_domain.com
        </Proxy>
EOF
fi
cd /etc/apache2/sites-available/
if [ ! -f template.$domain ] ; then
  cat > template.$domain <<EOF
<VirtualHost *>
    ServerName          template.$domain
    ProxyPass           / http://http_host/
    ProxyPassReverse    / http://http_host/
    ServerAdmin         root@$domain
    ErrorLog            /var/log/apache2/http_host-error.log
    CustomLog           /var/log/apache2/http_host-access.log common
</VirtualHost>

<VirtualHost *>
    ServerName          hg.template.$domain
    ProxyPass           / http://hg_host/
    ProxyPassReverse    / http://hg_host/
    ServerAdmin         root@$domain
    ErrorLog            /var/log/apache2/http_host-error.log
    CustomLog           /var/log/apache2/http_host-access.log common
</VirtualHost>
EOF
fi
sed -e "s/template/$name/g" -e "s/hg_host/$hg_host/g" -e "s/http_host/$http_host/g" < template.$domain > $name.$domain
a2ensite $name.$domain
/etc/init.d/apache2 reload
sleep 2
if [ ! -f /var/log/apache2/$http_host-error.log ] ; then
        echo "/var/log/apache2/$http_host-error.log does not exist"
        exit 1
fi
hg add $name.$domain
hg commit -u $author -m "define proxy for $name.$domain" $name.$domain
echo DONE
Write no code. The actual implementation must consist of configuration lines for each software involved. The implementation must be a set of configuration actions described to fit one or more use case.

A virtual machine is fully described in a XML file. A human or automated operator acts from a machine that has administration rights over the machines of the network. The operator instructs a machine to act on another machine. This action is made of a script, the description of the action to be interpreted by the script and the XML file describing the machine on which the action applies. For instance, the operator runs the "monitor machine" script on the Nagios machine and tells it to monitor the machine A by providing the A.xml file describing the machine.
/***
|''Name:''|GenerateRssByTagPlugin|
|''Description:''|Only tiddlers with a specific tag are inluded in the RSSFeed. If no tiddlers are selected then works as before. (see ticket #270: http://trac.tiddlywiki.org/tiddlywiki/ticket/270). <br>RssTag: <<option txtRssTag>>|
|''Version:''|1.0.3|
|''Date:''|May 17, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#GenerateRssByTagPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.GenerateRssByTagPlugin = {
	major: 1, minor: 0, revision: 3, 
	date: new Date("May 17, 2007"),
	source: 'http://tiddlywiki.bidix.info/#GenerateRssByTagPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	coreVersion: '2.2.0 (Beta 5)'
};

if (!window.bidix) window.bidix = {}; // bidix namespace

bidix.generateRssByTag = function()
{
	var s = [];
	var d = new Date();
	var u = store.getTiddlerText("SiteUrl");
	// Assemble the header
	s.push("<" + "?xml version=\"1.0\"" + " encoding='UTF-8' " + "?" + ">");
	s.push("<rss version=\"2.0\">");
	s.push("<channel>");
	s.push("<title" + ">" + wikifyPlain("SiteTitle").htmlEncode() + "</title" + ">");
	if(u)
		s.push("<link>" + u.htmlEncode() + "</link>");
	s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>");
	s.push("<language>en-us</language>");
	s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>");
	s.push("<pubDate>" + d.toGMTString() + "</pubDate>");
	s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>");
	s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
	s.push("<generator>TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + "</generator>");
	// The body
	var tiddlers;
	if (config.options.txtRssTag && store.getTaggedTiddlers(config.options.txtRssTag).length > 0)
		tiddlers = store.getTaggedTiddlers(config.options.txtRssTag,"modified");
	else
		tiddlers = store.getTiddlers("modified","excludeLists");
	var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems;
	for (var t=tiddlers.length-1; t>=n; t--)
		s.push(tiddlers[t].saveToRss(u));
	// And footer
	s.push("</channel>");
	s.push("</rss>");
	// Save it all
	return s.join("\n");
};

//
// Initializations
//
bidix.generateRss = generateRss; // backup core version
generateRss = bidix.generateRssByTag; // install new one
config.options.txtRssTag = "toRSS"; // default RssTag. use <<option txtRssTag>> to overwritte
merge(config.optionsDesc,{txtRssTag: "Only tiddlers with this tag will be included in the RSS Feed."});
//}}}
!Create lenny base
* create a 1GB lvm volume
* boot on Debian GNU/Linux lenny
* configure with LVM root and 20MB /boot
* add mercurial from http://hgcia.dachary.org/
* add ssh with no password
* add public ssh key from http://dachary.org/loic/id_rsa.pub
* empty root password in /etc/shadow
* create a virsh definition in /etc/libvirt/lenny.xml
{{{
<domain type='kvm'>
  <name>lenny</name>
  <memory>1000000</memory>
  <vcpu>2</vcpu>
  <os>
    <type arch="i686">hvm</type>
<!--
    <kernel>/boot/vmlinuz-2.6.26-1-686</kernel>
    <initrd>/boot/initrd.img-2.6.26-1-686</initrd>
    <cmdline>root=/dev/hda1 console=ttyS0 single</cmdline>
-->
<!--    <boot dev='cdrom' />-->
  </os>
  <clock sync="localtime"/>
  <devices>
    <emulator>/usr/bin/kvm</emulator>
    <disk type='file' device='disk'>
      <source file='/dev/all/lenny'/>
      <target dev='hda'/>
    </disk>
    <disk type='file' device='cdrom'>
      <source file='/home/xcdroast/debian-500-i386-netinst.iso'/>
      <target dev='hdc' bus='ide'/>
    </disk>
    <interface type='network'>
      <source network='default' />
    </interface>
    <graphics type='vnc' port='-1'/>
    <console tty='/dev/pts/5'/>
  </devices>
</domain>
}}}

!Create virtual machine A
* assign an IP in the lan from the lan DNS, with reverse ( ns1.tld )
* create a MAC with {{{echo $RANDOM | openssl md5 | sed 's/\(..\)/\1:/g' | cut -c1-17}}}
* copy lenny.xml (above) to A.xml
* add {{{<mac address='52:c7:ea:3d:41:03' />}}} to A.xml
* add a matching entry in the DHCP server, binding the MAC to the IP from the DNS
* boot the machine with {{{virsh create A.xml}}}
/***
| Name|HideWhenPlugin|
| Description|Allows conditional inclusion/exclusion in templates|
| Version|3.0 ($Rev: 1845 $)|
| Date|$Date: 2007-03-16 15:19:22 +1000 (Fri, 16 Mar 2007) $|
| Source|http://mptw.tiddlyspot.com/#HideWhenPlugin|
| Author|Simon Baird <simon.baird@gmail.com>|
| License|http://mptw.tiddlyspot.com/#TheBSDLicense|
For use in ViewTemplate and EditTemplate. Example usage:
{{{<div macro="showWhenTagged Task">[[TaskToolbar]]</div>}}}
{{{<div macro="showWhen tiddler.modifier == 'BartSimpson'"><img src="bart.gif"/></div>}}}
***/
//{{{

window.removeElementWhen = function(test,place) {
	if (test) {
		removeChildren(place);
		place.parentNode.removeChild(place);
	}
};

merge(config.macros,{

	hideWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( eval(paramString), place);
	}},

	showWhen: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( !eval(paramString), place);
	}},

	hideWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( tiddler.tags.containsAll(params), place);
	}},

	showWhenTagged: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( !tiddler.tags.containsAll(params), place);
	}},

	hideWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( tiddler.tags.containsAny(params), place);
	}},

	showWhenTaggedAny: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( !tiddler.tags.containsAny(params), place);
	}},

	hideWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( tiddler.tags.containsAll(params), place);
	}},

	showWhenTaggedAll: { handler: function (place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( !tiddler.tags.containsAll(params), place);
	}},

	hideWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0]), place);
	}},

	showWhenExists: { handler: function(place,macroName,params,wikifier,paramString,tiddler) {
		removeElementWhen( !(store.tiddlerExists(params[0]) || store.isShadowTiddler(params[0])), place);
	}}

});

//}}}

The context is a Debian etch GNU/Linux distribution.
[[Summary]]
[[Rationale]]
[[Use Cases]]
[[Scope]]
[[Design]]
[[Implementation]]
[[Unresolved Issues]]
[img[Cedre du barouk|images/small/Cedre du barouk.jpg][images/large/Cedre du barouk.jpg]]<<imagebox>>
# cmd openalpp osgal dachary.org /etc/bind
set -e
name="$1"
newname="$2"
domain="$3"
file="$4"
if grep -rl $name $file ; then
    grep -rl $name $file | xargs perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' 
    grep -rl $name $file | xargs perl -pi -e "s/\b$name\b/$newname/g"
    ! grep -rl $name $file
    /etc/init.d/bind9 reload
    sleep 1
    ! getent hosts $name.$domain
    getent hosts $newname.$domain
fi
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
parent="$(xmlstarlet sel -t -v /appliance//nagios/@parent < <(dog --no-header $meta))"
address="$(xmlstarlet sel -t -v /appliance//nagios/@address < <(dog --no-header $meta))"
cd /etc/nagios2/conf.d
cat >> $domain.cfg <<EOF
define host {
        host_name   $name
        port  8000 ???? check syntax
        parents     $parent
        alias       $name mercurial
        address     $address
        hostgroups  http-servers, debian-servers
        use         http-host
        }
EOF
/etc/init.d/nagios2 stop ; sleep 2; /etc/init.d/nagios2 start
hg commit -u $author -m "monitor $name" $domain.cfg
echo DONE
* some hardware are NFS servers
* to share DHCP configuration
* to share Proxy configuration
# cmd openalpp osgal dachary.org loic@dachary.org
set -e
name="$1"
newname="$2"
domain="$3"
author="$4"
cd /etc/nagios2/conf.d
grep -l $name $domain.cfg
perl -pi -e "s/\b$name\b/$newname/ if(/host_name.*$name/ .. /\}/)" $domain.cfg
! grep -l $name $domain.cfg
/etc/init.d/nagios2 stop
sleep 1
/etc/init.d/nagios2 start
hg commit -u $author -m "nagios rename $name into $newname" /etc/nagios2
** Proppy wants the apache appliance to access the ~MySQL appliance.
** Both appliances are on the same LAN.
** Proppy creates a view in the ~BIND9 DNS serving the apache appliance.
** The view is only active for the 192.168.50.0/24 addresses.
** Within this view a new top level domain name is availble : .conf.
** Proppy defines mysql.conf to be the IP address of the mysql software appliance.
** Proppy configures the phpmyadmin available on the apache appliance to use the ~MySQL database from the mysql.conf host.
** When the apache appliance is moved on another LAN, the DNS of this new LAN must bind mysql.conf to the appropriate IP address. 
** Proppy will not have to make changes within the software appliance as long as all references to resources on the LAN are named within the .conf top level domain name.
After {{{NameVirtualHost *}}} add the following so that it catches all unknown hostnames instead of being delivered to the first virtual host.
{{{
<VirtualHost _default_>
ServerName fake
</VirtualHost>
}}}

{{{
(03:08:09 PM) dachary: yo
(03:08:50 PM) dachary: un petit tip apache2 ?
(03:10:23 PM) gryzor: y a qu'a demander, mon bon Loic :)
(03:11:52 PM) dachary: alors alors
(03:11:54 PM) dachary: hum
(03:12:02 PM) dachary: mais qui tu me connais toi que je te connais ?
(03:12:43 PM) gryzor: de vue seulement
(03:12:56 PM) dachary: question: apache2 + virtual host : comment faire pour qu'un host qui n'est pas explicitement liste donne une erreur ?
(03:13:07 PM) dachary: ma question est pas hyper claire
(03:13:14 PM) gryzor: il suffit de faire donner une erreur par le 1er virtualhost
(03:13:22 PM) dachary: mais comment ?
(03:13:24 PM) gryzor: (donc, de le dedier a cela)
(03:13:27 PM) dachary: ah
(03:13:28 PM) dachary: ah
(03:13:31 PM) dachary: hum
(03:13:33 PM) dachary: ok
(03:13:40 PM) dachary: j'essaye
(03:13:41 PM) dachary: smart
(03:13:41 PM) fajita: smart is not enabled
(03:13:50 PM) gryzor: ou alors de definir un virtualhost qui s'appelle "_default_"
(03:14:53 PM) dachary: <VirtualHost _default_>
(03:14:57 PM) dachary: genre ca ?
(03:18:01 PM) dachary: hum
(03:18:13 PM) dachary: alors bon ca marche mais ca a des effets zarb
(03:19:52 PM) gryzor: faq1
(03:19:52 PM) fajita: The value of a NameVirtualHost directive has to match the content of <VirtualHost> exactly. For example, NameVirtualHost *:80 must be used with <VirtualHost *:80>
(03:20:47 PM) dachary: ...
(03:20:50 PM) dachary: ok
(03:20:57 PM) dachary: faq0 : url de la faq ?
(03:21:01 PM) dachary: nan j'abuse ;-)
(03:21:37 PM) dachary: <VirtualHost *>
(03:21:42 PM) dachary: ServerName pokersource.info
(03:21:48 PM) dachary: ServerAlias www.pokersource.info
(03:21:56 PM) dachary: et avant j'ai
(03:22:12 PM) dachary: <VirtualHost _default_>
(03:22:27 PM) dachary: et avant j'ai
(03:22:33 PM) dachary: NameVirtualHost *
(03:22:33 PM) fajita: NameVirtualHost * is 6usually what you want, if you only have one ip address
(03:22:43 PM) dachary: j'ai une seule IP
(03:22:58 PM) dachary: j'ai lu la faq mais la logique m'echape
(03:23:03 PM) dachary: *:80 ce n'est pas *exact*
(03:23:10 PM) dachary: pisque y'a un wildcard
(03:23:28 PM) dachary: donc je comprends pas ce que veut dire "exactly" dans ce contexte
(03:23:46 PM) dachary: ou alors il faut que je mette
(03:23:56 PM) dachary: NameVirtualHost pokersource.info:80
(03:23:58 PM) dachary: avant 
(03:24:08 PM) dachary: <VirtualHost pokersource.info:80>
(03:24:21 PM) dachary: je vais essayer ca
(03:24:32 PM) gryzor: non surtout pas
(03:24:41 PM) dachary: y'a un truc qui m'echape
(03:24:47 PM) dachary: ca doit etre enorme
(03:24:54 PM) gryzor: jamais de nom comme parametre a VirtualHost
(03:24:59 PM) gryzor: toujours une IP, ou une *
(03:25:07 PM) gryzor: ou _default&#195;_
(03:25:32 PM) gryzor: donc la conf avec * et _default_ est bonne
(03:25:36 PM) gryzor: tu as quoi comme effet de bord ?
(03:25:41 PM) dachary: ok
(03:26:01 PM) dachary: http://pokersource.info/ -> not found
(03:26:09 PM) dachary: http://www.pokersource.info/ -> ok
(03:26:16 PM) gryzor: ServerAlias
(03:26:16 PM) fajita: ServerAlias is http://httpd.apache.org/docs/2.2/mod/core.html#serveralias or http://httpd.apache.org/docs/1.3/mod/core.html#serveralias
(03:26:17 PM) dachary: j'ajoute le :80
(03:26:31 PM) dachary: je regarde
(03:26:43 PM) dachary: ServerAlias www.pokersource.info
(03:26:49 PM) gryzor: voila
(03:26:54 PM) dachary: j'ai ca deja
(03:26:59 PM) gryzor: et en ServerName
(03:27:03 PM) gryzor: ?
(03:27:52 PM) gryzor: dns www.pokersource.info
(03:27:53 PM) fajita: gryzor: www.pokersource.info is 88.191.250.37
(03:27:55 PM) dachary: ServerName pokersource.info
(03:27:55 PM) gryzor: dns pokersource.info
(03:27:55 PM) fajita: gryzor: pokersource.info is 88.191.250.37
(03:27:59 PM) dachary: voila
(03:28:20 PM) gryzor: aucun des 2 ne fonctionne
(03:28:26 PM) dachary: NameVirtualHost *
(03:28:26 PM) dachary: <VirtualHost _default_>
(03:28:26 PM) dachary: </VirtualHost>
(03:28:26 PM) dachary: <VirtualHost *>
(03:28:26 PM) dachary:         ServerName pokersource.info
(03:28:26 PM) dachary:         ServerAlias www.pokersource.info
(03:28:26 PM) dachary:  
(03:28:27 PM) fajita: NameVirtualHost * is 6usually what you want, if you only have one ip address
(03:28:29 PM) gryzor: The requested URL / was not found on this server.
(03:28:40 PM) gryzor: apc
(03:28:40 PM) fajita: Try using http://apache.pastebin.ca - It's a good pastebin, and is even set up to highlight Apache 'stuff'.
(03:28:44 PM) dachary: www.pokersource.info ne marche pas ??
(03:28:47 PM) gryzor: non
(03:28:52 PM) gryzor: vide ton cache
(03:29:00 PM) dachary: putain de firefox de mes couilles !!!!
(03:29:22 PM) dachary: :-)
(03:29:58 PM) dachary: hum
(03:30:10 PM) dachary: wget http://www.pokersource.info/ ca marche chez moi
(03:30:20 PM) dachary: je regarde les logs
(03:31:25 PM) gryzor: ok, maintenant oui
(03:32:04 PM) dachary: uof
(03:32:04 PM) dachary: ouf
(03:32:06 PM) dachary: :-)
(03:32:18 PM) dachary: par contre wget http://pokersource.info/ marche pas
(03:32:26 PM) dachary: avec la config ci dessus
(03:32:38 PM) gryzor: que dit le journal d'erreurs
(03:32:39 PM) gryzor: ?
(03:33:58 PM) dachary: file does not exist /htdocs
(03:34:10 PM) gryzor: paste config
(03:34:28 PM) gryzor: fajita: paste config
(03:34:28 PM) fajita: gryzor: i'm not following you...
(03:34:37 PM) gryzor: bon, 
(03:34:39 PM) gryzor: stupid bot
(03:34:39 PM) fajita: Dumb human.
(03:34:47 PM) dachary: http://hg.pokersource.info/file/7cde5a08ed7f/etc/apache2/sites-available/default
(03:34:54 PM) dachary: :-)
(03:35:01 PM) dachary: j'ai juste change le debut
(03:35:04 PM) dachary: de la config
(03:35:15 PM) dachary: comme montre ci dessus
(03:36:16 PM) gryzor: tout VirtualHost devrait avoir un ServerName
(03:36:50 PM) dachary: oh
(03:36:56 PM) dachary: y compris le premier _default_ ?
(03:37:07 PM) gryzor: oui
(03:37:14 PM) gryzor: meme si le nom est bidon
(03:37:16 PM) dachary: ah
(03:37:19 PM) dachary: je fais
(03:38:37 PM) dachary: http://hg.pokersource.info/file/a61226fbf24e/etc/apache2/sites-available/default
(03:38:39 PM) dachary: marche mieux
(03:38:41 PM) dachary: :-)
(03:38:52 PM) dachary: j'aurais JAMAIS trouve cette subtilite
(03:39:27 PM) gryzor: disons que c a ca que le support sert :)
(03:39:28 PM) dachary: c'est genial
(03:39:39 PM) dachary: ben bravo les gars
}}}
PasswordOptionPlugin is not compatible TiddlyWiki version 2.1.
See http://tiddlylab.bidix.info/#PasswordOptionPlugin
** Proppy wants to add a forum to the apache appliance.
** Using //hg incoming//, proppy checks if pending modifications from the publicly available apache appliance need to be transfererd to the copy running on his laptop.
** After applying the changes, proppy installs the forum.
** Proppy tests the forum and asks his friends to give it a try using the 37080 port that is being forwarded to his laptop.
** Turns out that the forum is a really bad software that requires too much work. 
** Proppy stops the apache appliance and revert to the state it was before trying the forum software using the //hg revert// command.
** When proppy is satisfied with the forum software installed, he creates a changeset and publishes it to the publicly available appliance. 
set -e
app=dog ; apt-get install -y --force-yes $app
app=xmlstarlet ; apt-get install -y --force-yes $app
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
url="$(xmlstarlet sel -t -v /appliance//garden/@url < <(dog --no-header $meta))"
seed="$(xmlstarlet sel -t -v /appliance//garden/@seed < <(dog --no-header $meta))"
mkdir -p /home/www
cd /home/www
wget -q "$url"
wget -q "$seed"
echo DONE
** Proppy wants to publish sensitive information as part of the software appliance
** The information is not essential for the appliance to work
** It's not extremely sensitive either, otherwise proppy would not publish it at all
** Proppy installs seahorse, the gnome cryptographic assistant
** Proppy uses nautilus to select the files or directories that he want to encrypt
** When asked by seahorse, proppy crypts the selected files for decryption by himself and a few others
** Proppy creates a skeleton vserver on the OS where a public IP was dedicated to the apache appliance.
** The skeleton vserver has a LAN IP that will receive incoming connections from the public IP.
** Proppy edits the DNS to define the .conf names required by the apache appliance.
** Proppy creates a mercurial repository at the root of the apache appliance.
** Proppy stops the apache appliance on his laptop.
** The apache appliance is rsync'ed from the laptop to the remote OS.
** Proppy starts the appliance on the remote OS and accesses it from the public IP.
When running a networked service there is a need to experiment with a clone while the original is still available to the public. Virtual machines can be created from a backup of an existing virtual machine. Switches, cables also have their virtual counter part and can mimic a real hardware.
pecho:~# meta=http://garden.conf.tld/packaging-farm.xml
pecho:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
pecho:~# echo $name
packaging-farm
pecho:~# vserver $name stop
*** output flushed ***
pecho:~# vserver $name status
*** output flushed ***
pecho:~# vserver $name status | grep stop
Vserver 'packaging-farm' is stopped
pecho:~#
dachary:~# meta=http://garden.conf.tld/packaging-farm.xml
dachary:~# echo $name.$domain
.
dachary:~# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
dachary:~# domain="$(xmlstarlet sel -t -v /appliance/@domain < <(dog --no-header $meta))"
dachary:~# author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
dachary:~# a2dissite $name.$domain
Site packaging-farm.dachary.org disabled; run /etc/init.d/apache2 reload to fully disable.
dachary:~# hg addremove /etc/apache2/
removing ../etc/apache2/sites-enabled/packaging-farm.dachary.org
dachary:~# rm -f /etc/apache2/sites-available/packaging-farm.dachary.org
dachary:~# hg addremove /etc/apache2/
removing ../etc/apache2/sites-available/packaging-farm.dachary.org
dachary:~# #hg commit -u $author -m "remove proxy for $name.$domain" /etc/apache2
dachary:~# hg status /etc/apache2
R ../etc/apache2/sites-available/packaging-farm.dachary.org
R ../etc/apache2/sites-enabled/packaging-farm.dachary.org
dachary:~# hg commit -u $author -m "remove proxy for $name.$domain" /etc/apache2
# rm /var/log/apache/*$name*
dachary:~# echo DONE
DONE
dachary:~#


dachary:/etc# meta=http://garden.conf.tld/packaging-farm.xml
dachary:/etc# name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header "$meta"))"
dachary:/etc# rss="$(xmlstarlet sel -t -v /appliance/rss/@url < <(dog --no-header "$meta"))"
dachary:/etc# echo $name
packaging-farm
dachary:/etc# #perl -pi -e '$_ = "" if(/\['$rss'/)' /etc/planet.conf
dachary:/etc# grep $rss /etc/planet.conf
http://packaging-farm.conf.tld:8000/rss-log
dachary:/etc# #perl -pi -e '$_ = "" if(/\['$rss'/)' /etc/planet.conf
dachary:/etc# grep $rss /etc/planet.conf
[http://packaging-farm.conf.tld:8000/rss-log]
dachary:/etc# perl -pi -e '$_ = "" if(/\['$rss'/)' /etc/planet.conf
Warning: Use of "log" without parentheses is ambiguous at -e line 1.
syntax error at -e line 1, near "tld:"
Search pattern not terminated at -e line 1.
dachary:/etc# perl -pi -e '$_ = "" if(|\['$rss'|)' /etc/planet.conf
Bareword found where operator expected at -e line 1, near "//packaging"
        (Missing operator before packaging?)
syntax error at -e line 1, near "(|"
Missing right curly or square bracket at -e line 1, at end of line
Execution of -e aborted due to compilation errors.
dachary:/etc# perl -pi -e '$_ = "" if(m|\['$rss'|)' /etc/planet.conf
dachary:/etc# grep $rss /etc/planet.conf
dachary:/etc# #perl -pi -e '$_ = "" if(m|^name = '$name'|)' /etc/planet.conf
dachary:/etc# grep '^name = '$name /etc/planet.conf
dachary:/etc# grep '^name = '$name /etc/planet.conf
name = packaging-farm
dachary:/etc# perl -pi -e '$_ = "" if(m|^name = '$name'|)' /etc/planet.conf
dachary:/etc# grep '^name = '$name /etc/planet.conf
dachary:/etc#


mkdir app
cd app
mkdir universe
ruby /usr/bin/tiddlywiki_cp -a http://garden.dachary.org/universe.html universe

author=loic@dachary.org
name=feed-reader
newname=yocto-reader
domain=dachary.org
file=/etc/bind
public_ns=ns2.fsffrance.org
scp universe/Modify\ a\ DNS\ entry\ to\ change\ a\ host\ name.tiddler root@$public_ns:/tmp/step1
ssh root@$public_ns sh -x /tmp/step1 $name $newname $domain $file $author

vserver_realm=fsf
realm=dachary
vserver_host=pecho.fsffrance.org
scp universe/Modify\ a\ DNS\ entry\ to\ change\ a\ host\ name.tiddler root@$vserver_host:/tmp/step2
ssh root@$vserver_host sh -x /tmp/step2 $name $newname $realm.$vserver_realm.tld $file $author

scp universe/Rename\ a\ vserver.tiddler root@$vserver_host:/tmp/step3
ssh root@$vserver_host sh -x /tmp/step3 $name $newname $author

proxy_vserver_host=pecho.fsffrance.org
proxy_name=dachary
scp universe/Apache\ proxy\ name\ change.tiddler root@$proxy_vserver_host:/var/lib/vservers/$proxy_name/tmp/step4
ssh root@$proxy_vserver_host vserver $proxy_name exec "sh -x /tmp/step4 $name $newname $domain $author"

nagios_vserver_host=mango.pokersource.info
nagios_name=nagiosfsf
scp universe/Nagios\ monitored\ vserver\ name\ change.tiddler root@$nagios_vserver_host:/var/lib/vservers/$nagios_name/tmp/step5
ssh root@$nagios_vserver_host vserver $nagios_name exec "sh -x /tmp/step5 $name $newname $domain $author"

rss_host=dachary.org
scp universe/Rename\ planet\ aggregated\ feed.tiddler root@$rss_host:/tmp/step6
ssh root@$rss_host sh -x /tmp/step6 $name $newname $author
[[Rename a software appliance (script)]]
# [[Modify a DNS entry to change a host name]] on the DNS hosting the public name
# [[Modify a DNS entry to change a host name]] on the VPN DNS
# [[Rename a VM]] with the new name
# [[Apache proxy name change]] with the new name
# [[Nagios monitored VM name change]] with the new name
# [[Rename planet aggregated feed]] with the new name
# cmd openalpp osgal 
set -e

name="$1"
newname="$2"

vserver $name stop
#http://oldwiki.linux-vserver.org/TweakingTheConfig
mv /etc/vservers/$name /etc/vservers/$newname
mv /var/lib/vservers/$name /var/lib/vservers/$newname
cd /etc/vservers/$newname
rm cache run vdir
ln -s /etc/vservers/.defaults/cachebase/$newname cache
ln -s /var/run/vservers/$newname run
ln -s /etc/vservers/.defaults/vdirbase/$newname vdir
xid=$(cat context)
rm /var/run/vservers.rev/$xid
ln -s /etc/vservers/$newname /var/run/vservers.rev/$xid
echo $newname > name
perl -pi -e "s/\b$name\b/$newname/" uts/nodename
grep -rl $name /var/lib/vservers/$newname/var/cache/mercurial/rss | xargs perl -pi -e "s/\b$name\b/$newname/" 
grep -rl $name /var/lib/vservers/$newname/etc/default /var/lib/vservers/$newname/etc/hosts | xargs perl -pi -e "s/\b$name\b/$newname/" 
vserver $newname start
# cmd openalpp osgal dachary.org loic@dachary.org
set -e
name="$1"
newname="$2"
author="$3"
cd /etc/
grep -l $name planet.conf
perl -pi -e "s/\b$name\b/$newname/" planet.conf
! grep -l $name planet.conf
for file in /var/cache/planet/*$name* ; do
    newfile=$(echo $file | perl -p -e "s/\b$name\b/$newname/g")
    mv $file $newfile
done
hg commit -u $author -m "planet rename $name into $newname" /etc/planet.conf
/***
| Name:|RenameTagsPlugin|
| Description:|Allows you to easily rename or delete tags across multiple tiddlers|
| Version:|3.0 ($Rev: 1845 $)|
| Date:|$Date: 2007-03-16 15:19:22 +1000 (Fri, 16 Mar 2007) $|
| Source:|http://mptw.tiddlyspot.com/#RenameTagsPlugin|
| Author:|Simon Baird <simon.baird@gmail.com>|
| License|http://mptw.tiddlyspot.com/#TheBSDLicense|
Rename a tag and you will be prompted to rename it in all its tagged tiddlers.
***/
//{{{
config.renameTags = {

	prompts: {
		rename: "Rename the tag '%0' to '%1' in %2 tidder%3?",
		remove: "Remove the tag '%0' from %1 tidder%2?"
	},

	removeTag: function(tag,tiddlers) {
		store.suspendNotifications();
		for (var i=0;i<tiddlers.length;i++) {
			store.setTiddlerTag(tiddlers[i].title,false,tag);
		}
		store.resumeNotifications();
		store.notifyAll();
	},

	renameTag: function(oldTag,newTag,tiddlers) {
		store.suspendNotifications();
		for (var i=0;i<tiddlers.length;i++) {
			store.setTiddlerTag(tiddlers[i].title,false,oldTag); // remove old
			store.setTiddlerTag(tiddlers[i].title,true,newTag);  // add new
		}
		store.resumeNotifications();
		store.notifyAll();
	},

	storeMethods: {

		saveTiddler_orig_renameTags: TiddlyWiki.prototype.saveTiddler,

		saveTiddler: function(title,newTitle,newBody,modifier,modified,tags,fields) {
			if (title != newTitle) {
				var tagged = this.getTaggedTiddlers(title);
				if (tagged.length > 0) {
					// then we are renaming a tag
					if (confirm(config.renameTags.prompts.rename.format([title,newTitle,tagged.length,tagged.length>1?"s":""])))
						config.renameTags.renameTag(title,newTitle,tagged);

					if (!this.tiddlerExists(title) && newBody == "")
						// dont create unwanted tiddler
						return null;
				}
			}
			return this.saveTiddler_orig_renameTags(title,newTitle,newBody,modifier,modified,tags,fields);
		},

		removeTiddler_orig_renameTags: TiddlyWiki.prototype.removeTiddler,

		removeTiddler: function(title) {
			var tagged = this.getTaggedTiddlers(title);
			if (tagged.length > 0)
				if (confirm(config.renameTags.prompts.remove.format([title,tagged.length,tagged.length>1?"s":""])))
					config.renameTags.removeTag(title,tagged);
			return this.removeTiddler_orig_renameTags(title);
		}

	},

	init: function() {
		merge(TiddlyWiki.prototype,this.storeMethods);
	}
}

config.renameTags.init();

//}}}

** Proppy wants to use his ssh private key from withing the vserver to gain write access to a SVN repository
** Proppy adds the following lines to /etc/vservers/pokerdev/fstab
{{{
/home/proppy /home/proppy	none bind 0 0
}}}
** Proppy mkdir /home/proppy within the vserver
** Proppy adds the following line in /etc/ssh/sshd_config
{{{
X11UseLocalhost no
}}}
** Proppy installs xauth so that X11 forwarding works
{{{
apt-get install xbase-clients
}}}
** Proppy creates the file /etc/hosts with the following content where pokerdev.pokersource.info is the hostname of the vserver and 192.168.70.18 is its IP
{{{
192.168.70.18 pokerdev.pokersource.info
}}}
** Proppy creates the user proppy making sure the uid matches his local machine uid (1000) in this case. He also inserts himself in the users group (100) so that other users of the same appliance can group with him.
{{{
adduser --gecos 'Proppy Aminche' --disabled-password  --uid 1000 --gid 100 proppy
}}}
** Proppy logs in the server using
{{{
ssh -X proppy@pokerdev
}}}
** Proppy apt-get install ssh-askpass or another package providing X11 based passphrase challenge
** Proppy sets the following environment variables when he wants to work as root. Although he prefers to work as himself, his home is not always available when in a remote location.
{{{
export SVN_SSH='ssh -i /home/proppy/.ssh/id_rsa'
export SSH_ASKPASS=/usr/lib/ssh/x11-ssh-askpass
}}}
** Proppy extracts a svn tree in /usr/src, making sure the directory have the setgid bit set to allow editing by other members of the users group
** Proppy installs emacs-snapshot because emacs does not have the svn-status command
** Proppy runs emacs, edit files, run svn-status and when commiting with svn-status gives his passphrase to write the repository
Vritual machines are meant to be used in the context of an online service. Average GNU/Linux system administration skills are required.

No software must be implemented. If a new ~BIND9 feature or a kvm feature is to be implemented, another specification has to be written.
including OS, cables, switches and firewalls
Software Appliances
http://garden.dachary.org/universe.html
Virtual machines such as kvm, xen or lxc can be connected using virtual cables  and switches and their access controled by firewalls. The network exposes interfaces to the general public. It is also visible thru a VPN for authors and administrators. The ealth of all resources in the network is monitored with nagios and munin.

The hosting facility is an aggregate of machines located in different data centers. Each of them uses a firewall to chose which ports are visible to the general public for the IP that are routed to it. Each IP is bound to a domain name by a DNS. 

When the firewall receives a request (for instance to get a web page from http://garden.dachary.org/), it routes it to a virtual machine hidden from the public. The virtual machine can be located on the same hardware as the firewall or on another hardware. 

The IP addresses used for the virtual machines are private and routes are established between them using a VPN. For instance, a machine located in Paris could use 192.168.25.0/24 and route all 192.168.14.0/24 to a machine located in Amsterdam.

The private addresses are bound to a DNS that is only accessible from within the VPN. Each LAN runs a slave of the primary private DNS. This ensures that the DHCP server that provides IP addresses to each VM is always able to do so, even when the primary DNS goes down. There is only one DHCP server configuration, duplicated on each LAN. The configuration is shared by a NFS mounted mercurial repository.

Each LAN has a http proxy to reduce the need for public IP for services that only provide a HTTP interface. The http proxy configuration is shared with mercurial repositories on all LAN. 

All scripts handling the virtual machines are based on libvirt. The backend is KVM on hardware with VT support, Xen on the others. When appropriate LXC is chosen to reduce the resource usage to a minimum. 

The virtual machines are all connected to a bridge that is considered as the LAN for a given machine. When a LAN consist of more than one machine, one of them acts as the firewall and DHCP server. The others bind their physical interface to a bridge and are transparent to the virtual machines they host. 

Each virtual machine is provided with a LVM volume containing a partitioned disk. The typical pre-formated virtual machine has a swap, boot and root. If the disk needs to be bigger than the default (1GB), a partition is created and extends the root LVM volume. 

The LVM volumes are duplicated using DRBD on machines that are not in the same location. When a hardware fails, or a data center becomes unavailable, the backup can take over with minimal loss. The backups are handled using rsync full incremental backups with a rotation when more than 300GB, 10M inodes are used or 6 months have passed.

Each virtual machine and the VPN, DNS and firewalls is monitored with nagios and graphed with munin.
set -e
meta="$1"
name="$(xmlstarlet sel -t -v /appliance/@name < <(dog --no-header $meta))"
rss="$(xmlstarlet sel -t -v /appliance/rss/@url < <(dog --no-header $meta))"
echo "[$rss]" >> /etc/planet.conf
echo "name = $name" >> /etc/planet.conf
su www-data -c 'planetplanet -v /etc/planet.conf'
echo DONE
/***
| Name|TagglyTaggingPlugin|
| Description|tagglyTagging macro is a replacement for the builtin tagging macro in your ViewTemplate|
| Version|3.1 ($Rev: 2341 $)|
| Date|$Date: 2007-07-05 10:02:27 +1000 (Thu, 05 Jul 2007) $|
| Source|http://mptw.tiddlyspot.com/#TagglyTaggingPlugin|
| Author|Simon Baird <simon.baird@gmail.com>|
| License|http://mptw.tiddlyspot.com/#TheBSDLicense|
!Notes
See http://mptw.tiddlyspot.com/#TagglyTagging
***/
//{{{
config.taggly = {

	// for translations
	lingo: {
		labels: {
			asc:        "\u2191", // down arrow
			desc:       "\u2193", // up arrow
			title:      "title",
			modified:   "modified",
			created:    "created",
			show:       "+",
			hide:       "-",
			normal:     "normal",
			group:      "group",
			commas:     "commas",
			sitemap:    "sitemap",
			numCols:    "cols\u00b1", // plus minus sign
			label:      "Tagged as '%0':",
			excerpts:   "excerpts",
			contents:   "contents",
			sliders:    "sliders",
			noexcerpts: "title only"
		},

		tooltips: {
			title:    "Click to sort by title",
			modified: "Click to sort by modified date",
			created:  "Click to sort by created date",
			show:     "Click to show tagging list",
			hide:     "Click to hide tagging list",
			normal:   "Click to show a normal ungrouped list",
			group:    "Click to show list grouped by tag",
			sitemap:  "Click to show a sitemap style list",
			commas:   "Click to show a comma separated list",
			numCols:  "Click to change number of columns",
			excerpts: "Click to show excerpts",
			contents: "Click to show entire tiddler contents",
			sliders:  "Click to show tiddler contents in sliders",
			noexcerpts: "Click to show entire title only"
		}
	},

	config: {
		showTaggingCounts: true,
		listOpts: {
			// the first one will be the default
			sortBy:     ["title","modified","created"],
			sortOrder:  ["asc","desc"],
			hideState:  ["show","hide"],
			listMode:   ["normal","group","sitemap","commas"],
			numCols:    ["1","2","3","4","5","6"],
			excerpts:   ["noexcerpts","excerpts","contents","sliders"]
		},
		valuePrefix: "taggly.",
		excludeTags: ["excludeLists","excludeTagging"],
		excerptSize: 50,
		excerptMarker: "/%"+"%/"
	},

	getTagglyOpt: function(title,opt) {
		var val = store.getValue(title,this.config.valuePrefix+opt);
		return val ? val : this.config.listOpts[opt][0];
	},

	setTagglyOpt: function(title,opt,value) {
		if (!store.tiddlerExists(title))
			// create it silently
			store.saveTiddler(title,title,config.views.editor.defaultText.format([title]),config.options.txtUserName,new Date(),null);
		// if value is default then remove it to save space
		return store.setValue(title,
			this.config.valuePrefix+opt,
			value == this.config.listOpts[opt][0] ? null : value);
	},

	getNextValue: function(title,opt) {
		var current = this.getTagglyOpt(title,opt);
		var pos = this.config.listOpts[opt].indexOf(current);
		// a little usability enhancement. actually it doesn't work right for grouped or sitemap
		var limit = (opt == "numCols" ? store.getTaggedTiddlers(title).length : this.config.listOpts[opt].length);
		var newPos = (pos + 1) % limit;
		return this.config.listOpts[opt][newPos];
	},

	toggleTagglyOpt: function(title,opt) {
		var newVal = this.getNextValue(title,opt);
		this.setTagglyOpt(title,opt,newVal);
	}, 

	createListControl: function(place,title,type) {
		var lingo = config.taggly.lingo;
		var label;
		var tooltip;
		var onclick;

		if ((type == "title" || type == "modified" || type == "created")) {
			// "special" controls. a little tricky. derived from sortOrder and sortBy
			label = lingo.labels[type];
			tooltip = lingo.tooltips[type];

			if (this.getTagglyOpt(title,"sortBy") == type) {
				label += lingo.labels[this.getTagglyOpt(title,"sortOrder")];
				onclick = function() {
					config.taggly.toggleTagglyOpt(title,"sortOrder");
					return false;
				}
			}
			else {
				onclick = function() {
					config.taggly.setTagglyOpt(title,"sortBy",type);
					config.taggly.setTagglyOpt(title,"sortOrder",config.taggly.config.listOpts.sortOrder[0]);
					return false;
				}
			}
		}
		else {
			// "regular" controls, nice and simple
			label = lingo.labels[type == "numCols" ? type : this.getNextValue(title,type)];
			tooltip = lingo.tooltips[type == "numCols" ? type : this.getNextValue(title,type)];
			onclick = function() {
				config.taggly.toggleTagglyOpt(title,type);
				return false;
			}
		}

		// hide button because commas don't have columns
		if (!(this.getTagglyOpt(title,"listMode") == "commas" && type == "numCols"))
			createTiddlyButton(place,label,tooltip,onclick,type == "hideState" ? "hidebutton" : "button");
	},

	makeColumns: function(orig,numCols) {
		var listSize = orig.length;
		var colSize = listSize/numCols;
		var remainder = listSize % numCols;

		var upperColsize = colSize;
		var lowerColsize = colSize;

		if (colSize != Math.floor(colSize)) {
			// it's not an exact fit so..
			upperColsize = Math.floor(colSize) + 1;
			lowerColsize = Math.floor(colSize);
		}

		var output = [];
		var c = 0;
		for (var j=0;j<numCols;j++) {
			var singleCol = [];
			var thisSize = j < remainder ? upperColsize : lowerColsize;
			for (var i=0;i<thisSize;i++) 
				singleCol.push(orig[c++]);
			output.push(singleCol);
		}

		return output;
	},

	drawTable: function(place,columns,theClass) {
		var newTable = createTiddlyElement(place,"table",null,theClass);
		var newTbody = createTiddlyElement(newTable,"tbody");
		var newTr = createTiddlyElement(newTbody,"tr");
		for (var j=0;j<columns.length;j++) {
			var colOutput = "";
			for (var i=0;i<columns[j].length;i++) 
				colOutput += columns[j][i];
			var newTd = createTiddlyElement(newTr,"td",null,"tagglyTagging"); // todo should not need this class
			wikify(colOutput,newTd);
		}
		return newTable;
	},

	createTagglyList: function(place,title) {
		switch(this.getTagglyOpt(title,"listMode")) {
			case "group":  return this.createTagglyListGrouped(place,title); break;
			case "normal": return this.createTagglyListNormal(place,title,false); break;
			case "commas": return this.createTagglyListNormal(place,title,true); break;
			case "sitemap":return this.createTagglyListSiteMap(place,title); break;
		}
	},

	getTaggingCount: function(title) {
		// thanks to Doug Edmunds
		if (this.config.showTaggingCounts) {
			var tagCount = store.getTaggedTiddlers(title).length;
			if (tagCount > 0)
				return " ("+tagCount+")";
		}
		return "";
	},

	getExcerpt: function(inTiddlerTitle,title,indent) {
    if (!indent)
			indent = 1;
		if (this.getTagglyOpt(inTiddlerTitle,"excerpts") == "excerpts") {
			var t = store.getTiddler(title);
			if (t) {
				var text = t.text.replace(/\n/," ");
				var marker = text.indexOf(this.config.excerptMarker);
				if (marker != -1) {
					return " {{excerpt{<nowiki>" + text.substr(0,marker) + "</nowiki>}}}";
				}
				else if (text.length < this.config.excerptSize) {
					return " {{excerpt{<nowiki>" + t.text + "</nowiki>}}}";
				}
				else {
					return " {{excerpt{<nowiki>" + t.text.substr(0,this.config.excerptSize) + "..." + "</nowiki>}}}";
				}
			}
		}
		else if (this.getTagglyOpt(inTiddlerTitle,"excerpts") == "contents") {
			var t = store.getTiddler(title);
			if (t) {
				return "\n{{contents indent"+indent+"{\n" + t.text + "\n}}}";
			}
		}
		else if (this.getTagglyOpt(inTiddlerTitle,"excerpts") == "sliders") {
			var t = store.getTiddler(title);
			if (t) {
				return "<slider slide>\n{{contents{\n" + t.text + "\n}}}\n</slider>";
			}
		}
		return "";
	},

	notHidden: function(t,inTiddler) {
		if (typeof t == "string") 
			t = store.getTiddler(t);
		return (!t || !t.tags.containsAny(this.config.excludeTags) ||
				(inTiddler && this.config.excludeTags.contains(inTiddler)));
	},

	// this is for normal and commas mode
	createTagglyListNormal: function(place,title,useCommas) {

		var list = store.getTaggedTiddlers(title,this.getTagglyOpt(title,"sortBy"));

		if (this.getTagglyOpt(title,"sortOrder") == "desc")
			list = list.reverse();

		var output = [];
		var first = true;
		for (var i=0;i<list.length;i++) {
			if (this.notHidden(list[i],title)) {
				var countString = this.getTaggingCount(list[i].title);
				var excerpt = this.getExcerpt(title,list[i].title);
				if (useCommas)
					output.push((first ? "" : ", ") + "[[" + list[i].title + "]]" + countString + excerpt);
				else
					output.push("*[[" + list[i].title + "]]" + countString + excerpt + "\n");

				first = false;
			}
		}

		return this.drawTable(place,
			this.makeColumns(output,useCommas ? 1 : parseInt(this.getTagglyOpt(title,"numCols"))),
			useCommas ? "commas" : "normal");
	},

	// this is for the "grouped" mode
	createTagglyListGrouped: function(place,title) {
		var sortBy = this.getTagglyOpt(title,"sortBy");
		var sortOrder = this.getTagglyOpt(title,"sortOrder");

		var list = store.getTaggedTiddlers(title,sortBy);

		if (sortOrder == "desc")
			list = list.reverse();

		var leftOvers = []
		for (var i=0;i<list.length;i++)
			leftOvers.push(list[i].title);

		var allTagsHolder = {};
		for (var i=0;i<list.length;i++) {
			for (var j=0;j<list[i].tags.length;j++) {

				if (list[i].tags[j] != title) { // not this tiddler

					if (this.notHidden(list[i].tags[j],title)) {

						if (!allTagsHolder[list[i].tags[j]])
							allTagsHolder[list[i].tags[j]] = "";

						if (this.notHidden(list[i],title)) {
							allTagsHolder[list[i].tags[j]] += "**[["+list[i].title+"]]"
										+ this.getTaggingCount(list[i].title) + this.getExcerpt(title,list[i].title) + "\n";

							leftOvers.setItem(list[i].title,-1); // remove from leftovers. at the end it will contain the leftovers

						}
					}
				}
			}
		}

		var allTags = [];
		for (var t in allTagsHolder)
			allTags.push(t);

		var sortHelper = function(a,b) {
			if (a == b) return 0;
			if (a < b) return -1;
			return 1;
		};

		allTags.sort(function(a,b) {
			var tidA = store.getTiddler(a);
			var tidB = store.getTiddler(b);
			if (sortBy == "title") return sortHelper(a,b);
			else if (!tidA && !tidB) return 0;
			else if (!tidA) return -1;
			else if (!tidB) return +1;
			else return sortHelper(tidA[sortBy],tidB[sortBy]);
		});

		var leftOverOutput = "";
		for (var i=0;i<leftOvers.length;i++)
			if (this.notHidden(leftOvers[i],title))
				leftOverOutput += "*[["+leftOvers[i]+"]]" + this.getTaggingCount(leftOvers[i]) + this.getExcerpt(title,leftOvers[i]) + "\n";

		var output = [];

		if (sortOrder == "desc")
			allTags.reverse();
		else if (leftOverOutput != "")
			// leftovers first...
			output.push(leftOverOutput);

		for (var i=0;i<allTags.length;i++)
			if (allTagsHolder[allTags[i]] != "")
				output.push("*[["+allTags[i]+"]]" + this.getTaggingCount(allTags[i]) + this.getExcerpt(title,allTags[i]) + "\n" + allTagsHolder[allTags[i]]);

		if (sortOrder == "desc" && leftOverOutput != "")
			// leftovers last...
			output.push(leftOverOutput);

		return this.drawTable(place,
				this.makeColumns(output,parseInt(this.getTagglyOpt(title,"numCols"))),
				"grouped");

	},

	// used to build site map
	treeTraverse: function(title,depth,sortBy,sortOrder) {

		var list = store.getTaggedTiddlers(title,sortBy);
		if (sortOrder == "desc")
			list.reverse();

		var indent = "";
		for (var j=0;j<depth;j++)
			indent += "*"

		var childOutput = "";
		for (var i=0;i<list.length;i++)
			if (list[i].title != title)
				if (this.notHidden(list[i].title,this.config.inTiddler))
					childOutput += this.treeTraverse(list[i].title,depth+1,sortBy,sortOrder);

		if (depth == 0)
			return childOutput;
		else
			return indent + "[["+title+"]]" + this.getTaggingCount(title) + this.getExcerpt(this.config.inTiddler,title,depth) + "\n" + childOutput;
	},

	// this if for the site map mode
	createTagglyListSiteMap: function(place,title) {
		this.config.inTiddler = title; // nasty. should pass it in to traverse probably
		var output = this.treeTraverse(title,0,this.getTagglyOpt(title,"sortBy"),this.getTagglyOpt(title,"sortOrder"));
		return this.drawTable(place,
				this.makeColumns(output.split(/(?=^\*\[)/m),parseInt(this.getTagglyOpt(title,"numCols"))), // regexp magic
				"sitemap"
				);
	},

	macros: {
		tagglyTagging: {
			handler: function (place,macroName,params,wikifier,paramString,tiddler) {
				var refreshContainer = createTiddlyElement(place,"div");
				// do some refresh magic to make it keep the list fresh - thanks Saq
				refreshContainer.setAttribute("refresh","macro");
				refreshContainer.setAttribute("macroName",macroName);
        			refreshContainer.setAttribute("title",tiddler.title);
				this.refresh(refreshContainer);
			},

			refresh: function(place) {
				var title = place.getAttribute("title");
				removeChildren(place);
				if (store.getTaggedTiddlers(title).length > 0) {
					var lingo = config.taggly.lingo;
					config.taggly.createListControl(place,title,"hideState");
					if (config.taggly.getTagglyOpt(title,"hideState") == "show") {
						createTiddlyElement(place,"span",null,"tagglyLabel",lingo.labels.label.format([title]));
						config.taggly.createListControl(place,title,"title");
						config.taggly.createListControl(place,title,"modified");
						config.taggly.createListControl(place,title,"created");
						config.taggly.createListControl(place,title,"listMode");
						config.taggly.createListControl(place,title,"excerpts");
						config.taggly.createListControl(place,title,"numCols");
						config.taggly.createTagglyList(place,title);
					}
				}
			}
		}
	},

	// todo fix these up a bit
	styles: [
"/*{{{*/",
"/* created by TagglyTaggingPlugin */",
".tagglyTagging { padding-top:0.5em; }",
".tagglyTagging li.listTitle { display:none; }",
".tagglyTagging ul {",
"	margin-top:0px; padding-top:0.5em; padding-left:2em;",
"	margin-bottom:0px; padding-bottom:0px;",
"}",
".tagglyTagging { vertical-align: top; margin:0px; padding:0px; }",
".tagglyTagging table { margin:0px; padding:0px; }",
".tagglyTagging .button { visibility:hidden; margin-left:3px; margin-right:3px; }",
".tagglyTagging .button, .tagglyTagging .hidebutton {",
"	color:[[ColorPalette::TertiaryLight]]; font-size:90%;",
"	border:0px; padding-left:0.3em;padding-right:0.3em;",
"}",
".tagglyTagging .button:hover, .hidebutton:hover, ",
".tagglyTagging .button:active, .hidebutton:active  {",
"	border:0px; background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]];",
"}",
".selected .tagglyTagging .button { visibility:visible; }",
".tagglyTagging .hidebutton { color:[[ColorPalette::Background]]; }",
".selected .tagglyTagging .hidebutton { color:[[ColorPalette::TertiaryLight]] }",
".tagglyLabel { color:[[ColorPalette::TertiaryMid]]; font-size:90%; }",
".tagglyTagging ul {padding-top:0px; padding-bottom:0.5em; margin-left:1em; }",
".tagglyTagging ul ul {list-style-type:disc; margin-left:-1em;}",
".tagglyTagging ul ul li {margin-left:0.5em; }",
".editLabel { font-size:90%; padding-top:0.5em; }",
".tagglyTagging .commas { padding-left:1.8em; }",
"/* not technically tagglytagging but will put them here anyway */",
".tagglyTagged li.listTitle { display:none; }",
".tagglyTagged li { display: inline; font-size:90%; }",
".tagglyTagged ul { margin:0px; padding:0px; }",
".excerpt { color:[[ColorPalette::TertiaryDark]]; }",
"div.tagglyTagging table,",
"div.tagglyTagging table tr,",
"td.tagglyTagging",
" {border-style:none!important; }",
".tagglyTagging .contents { border-bottom:2px solid [[ColorPalette::TertiaryPale]]; padding:0 1em 1em 0.5em;",
"  margin-bottom:0.5em; }",
".tagglyTagging .indent1  { margin-left:3em;  }",
".tagglyTagging .indent2  { margin-left:4em;  }",
".tagglyTagging .indent3  { margin-left:5em;  }",
".tagglyTagging .indent4  { margin-left:6em;  }",
".tagglyTagging .indent5  { margin-left:7em;  }",
".tagglyTagging .indent6  { margin-left:8em;  }",
".tagglyTagging .indent7  { margin-left:9em;  }",
".tagglyTagging .indent8  { margin-left:10em; }",
".tagglyTagging .indent9  { margin-left:11em; }",
".tagglyTagging .indent10 { margin-left:12em; }",
"/*}}}*/",
		""].join("\n"),

	init: function() {
		merge(config.macros,this.macros);
		config.shadowTiddlers["TagglyTaggingStyles"] = this.styles;
		store.addNotification("TagglyTaggingStyles",refreshStyles);
	}
};

config.taggly.init();

//}}}

/***
InlineSlidersPlugin
By Saq Imtiaz
http://tw.lewcid.org/sandbox/#InlineSlidersPlugin

// syntax adjusted to not clash with NestedSlidersPlugin

***/
//{{{
config.formatters.unshift( {
	name: "inlinesliders",
	// match: "\\+\\+\\+\\+|\\<slider",
	match: "\\<slider",
	// lookaheadRegExp: /(?:\+\+\+\+|<slider) (.*?)(?:>?)\n((?:.|\n)*?)\n(?:====|<\/slider>)/mg,
	lookaheadRegExp: /(?:<slider) (.*?)(?:>)\n((?:.|\n)*?)\n(?:<\/slider>)/mg,
	handler: function(w) {
		this.lookaheadRegExp.lastIndex = w.matchStart;
		var lookaheadMatch = this.lookaheadRegExp.exec(w.source)
		if(lookaheadMatch && lookaheadMatch.index == w.matchStart ) {
			var btn = createTiddlyButton(w.output,lookaheadMatch[1] + " "+"\u00BB",lookaheadMatch[1],this.onClickSlider,"button sliderButton");
			var panel = createTiddlyElement(w.output,"div",null,"sliderPanel");
			panel.style.display = "none";
			wikify(lookaheadMatch[2],panel);
			w.nextMatch = lookaheadMatch.index + lookaheadMatch[0].length;
		}
   },
   onClickSlider : function(e) {
		if(!e) var e = window.event;
		var n = this.nextSibling;
		n.style.display = (n.style.display=="none") ? "block" : "none";
		return false;
	}
});

//}}}

/***
|''Name:''|TiddlyLightBox|
|''Date:''|Jan 1, 2006|
|''Version:''|1.0 beta|
|''Author:''|Saq Imtiaz|
|''Location:''|http://tw.lewcid.org/#TiddlyLightBoxPlugin|
|''Documentation:''|http://tw.lewcid.org/#TiddlyLightBoxDocs|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''Based on:''|DC3.LightBox<br>Light Box Gone Wild <br>Ibox|

!!Code
***/
//{{{
config.macros.imagebox ={};
config.macros.imagebox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    var e = place.lastChild;
    e.onclick = function(){TiddlyLightBox.initBox('image',this,params[1],params[2],params[0]);return false;};
}

config.macros.divbox ={};
config.macros.divbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    if (params[0]!=".")
        createTiddlyButton(place,params[0],params[0],function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;});
    else
        {
        var e = place.lastChild;
        e.onclick = function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;};
        }
}

config.macros.tiddlerbox ={}
config.macros.tiddlerbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    config.macros.divbox.handler(place,macroName,[params[0],"tiddler:"+params[1],params[2],params[3],params[4]]);
    return false;
}

store.addNotification("TiddlyLightBoxStyles",refreshStyles);

if (!window.TiddlyLightBox)
    window.TiddlyLightBox = {};
    var loadingImage = "indicator.gif";
    window.TiddlyLightBox =
    {
    _curBox: null, // [sentinel]

    lightBoxHtml : '<div id="lightBoxOverlay" onclick="TiddlyLightBox.hideBox()" style="display:none"></div><div id="lightboxprogress" style="display:none;"><img src=\''+loadingImage+'\' alt=\'loading\' style="width:128px;height:128px;"></div><div class="lightBox" id="lightBox" style="display:none"><div id="lightBoxContent"></div><div id="lightBoxTitle">This is a title</div><div id="lightBoxClose"><a href:"#" onclick="TiddlyLightBox.hideBox();return false;">Click to close</a></div></div>',

    createBoxWrapper : function()
        {
        var wrapper = createTiddlyElement(document.getElementsByTagName("body")[0],"div","tiddlyLightBoxWrapper");
        wrapper.innerHTML = this.lightBoxHtml;
        },

    initBox : function(contentType,url,w,h,text)
        {
        if (this._curBox)
            return;
        this.showProgress();
        this.hideSelects("hidden");
        this.showBg();
        this._curBox = true;
        this.sizeTheBox(contentType,w,h);
        if (contentType == 'image')
            this.showImage(url,text);
        else if (contentType == 'html')
            this.showHtml(url,text);
        return false;
        },
        
    sizeTheBox : function(contentType,w,h)
        {
        var box = document.getElementById("lightBoxContent");
        if (w && isNaN(parseInt(w)))
            {
            addClass(box,w);
            }
        else if (w ||h || contentType == 'html')
            {
            box.style.width = w? w+ "px" : "450px";
            box.style.height = h? h+ "px" : "280px";
            if (contentType=='image')
                setStylesheet("#lightBoxContent img{height:100%;width:100%;}","lightBoxImageSizeHack");
            }
        },

    showProgress : function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='';
        this._center(progress);
        },
    
    hideProgress: function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='none';
        },

    //this function lifted from Lightbox Gone Wild
    hideSelects: function(visibility)
        {
        var selects = document.getElementsByTagName('select');
        for(i = 0; i < selects.length; i++)
            {
            selects[i].style.visibility = visibility;
            }
        },

    showBg: function()
        {
        var overlay = document.getElementById('lightBoxOverlay');
        if (config.browser.isIE)
            {
            overlay.style.height = Math.max(document.documentElement.scrollHeight,document.documentElement.offsetHeight);
            overlay.style.width = document.documentElement.scrollWidth;
            }
        overlay.style.display = 'block';
        },

    showImage: function (url,text)
        {
        imgPreloader = new Image();
        imgPreloader.onload = function ()
            {
            var lb = document.getElementById("lightBoxContent");
            lb.innerHTML = "<img src="+url+">";
            lb.onclick = function(){TiddlyLightBox.hideBox();return false;};
            TiddlyLightBox.posBox(text);
            };
        imgPreloader.src = url;
        },
        
    showHtml : function(theID,text)
        {
        var lb = document.getElementById("lightBoxContent");
        if (theID.indexOf("tiddler:")==-1)
             lb.innerHTML = document.getElementById(theID).innerHTML;
        else
            { 
             wikify(store.getTiddlerText(theID.replace("tiddler:","")),lb);
             lb.className='tiddler';
            }
        lb.style.overflow = "auto";
        this.posBox(text);
        },

    posBox: function(text)
       {
       this.setTitle(text);
       this.hideProgress();
       var lb = document.getElementById("lightBox");
       lb.style.display = "";
       lb.style.visibilty = "hidden";
       lb.style.position = "absolute";
       this._center(lb);
       if(!TiddlyLightBox._curBox) return;
       lb.style.visibility = "visible";
       lb.style.display = "block";
       },

     setTitle: function(text)
        {
        document.getElementById("lightBoxTitle").innerHTML=  (text==undefined)? '': text;
        },

    _center: function(lb)
       {
       var lbSize = new TiddlyLightBox.getElementSize(lb);
       lb.style.left = (Math.round(findWindowWidth()/2) - (lbSize.width /2) + findScrollX())+'px';
       lb.style.top = (Math.round(findWindowHeight()/2) - (lbSize.height /2) + findScrollY())+'px';
       },

    //this function lifted from Ibox
    getElementSize : function(elem)
       {
       this.width = elem.offsetWidth || elem.style.pixelWidth;
       this.height = elem.offsetHeight || elem.style.pixelHeight;
       },

     hideBox: function()
         {
         if(!this._curBox)
             return;
         document.getElementById("tiddlyLightBoxWrapper").innerHTML= this.lightBoxHtml;
         setStylesheet("","lightBoxImageSizeHack");
         this._curBox = null;
         return false;
         }
}

TiddlyLightBox.createBoxWrapper();

Story.prototype.findContainingTiddler = function(e)
{
    while(e && (!hasClass(e,"tiddler") || !e.getAttribute("tiddler")))
        e = e.parentNode;
    return(e);
}

config.shadowTiddlers.TiddlyLightBoxStyles="/*{{{*/\n#lightBoxOverlay {\n position:absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 90; \n background-color: #000;\n -moz-opacity: 0.75;\n opacity: .75;\n filter: alpha(opacity=75);\n}\n#lightBoxOverlay[id]{ \n position: fixed;\n}\n\n#lightboxprogress { \n margin:0;padding:0;\n position: absolute;\n z-index:95;\n}\n\ndiv.lightBox {\n background: #fff;\n color: #fff;\n border: 4px solid #525252;\npadding:20px 20px 25px 20px; position:absolute; z-index:99;\n}\n\n#lightBoxClose {text-align:right; color:#000; font-size:1.0em; position:absolute; bottom:6px; right:20px;}\n#lightBoxClose a{color:#666; border-bottom:1px solid #666;cursor:pointer;}\n#lightBoxClose a:hover {color:#111; border-bottom:1px solid #666; cursor:pointer; background:transparent;}\n\n#lightBoxContent {border:1px solid #525252;color:#000; background:#fff;}\n#lightBox .tiddler {background:#fff;}\n\n#lightBoxContent img {border:0;margin:0;padding:0;display:block;cursor:pointer;}\n\n#lightBoxTitle {padding:0px; font-weight:bold; position:absolute; left:20px;bottom:6px; font-size:1.1em; color:#000;}\n\n/*}}}*/";
//}}}
* When a package installation spans more than one software appliance (forum installation implying database configuration) the result can't be published with mercurial.
* The content of a database is usualy stored in binary form and text based tools can't be used for backups.
* mercurial does not handle symbolic links or empty directories (0.9.3)
* ''X11 forwarding depends on a match between the IP and the hostname (either from the DNS or from hosts)''
* /etc/resolv.conf must list an IP that depends on the DNS address available on a given vserver host. There is maybe a way to update this globaly from /etc/vserver 
* //hg pull// can't be used in [[Patching the apache appliance]] because the hg protocol transmits too many information and it lasts for ages. This is not going to change any time soon.

<<<
With a //linux-2.6// kernel, creating a virtual ethernet interface is made easy. 
{{{
apt-get install vlan
}}}
provides the extensions needed for ///etc/network/interfaces//. To create the //eth0.2// interface add the following lines to ///etc/network/interfaces//.
//sources.list// and //resolv.conf// are to be modified when moving the appliance because they are geographicaly dependent.
{{{
auto eth0.2
iface eth0.2 inet static
        address 192.168.50.1
        netmask 255.255.255.0
	pre-up modprobe 8021q
#	up iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
#	up iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
	up echo 0 > /proc/sys/net/ipv4/conf/eth0.2/rp_filter

}}}
Note that once this is done, packets originating from the 192.168.50.0/24 subnet won't be routed because the MASQUERADE lines are commented out. Routing is being dealt with by shorewall. However, if you don't have or don't want shorewall, the MASQUERADE lines will do the work.
<<<
set -e
meta="$1"
mercurial_repository="$(xmlstarlet sel -t -v /appliance/vserver_master/mercurial/@repository < <(dog --no-header $meta))"
url="$(xmlstarlet sel -t -v /appliance//mercurial/@url < <(dog --no-header $meta))"
author="$(xmlstarlet sel -t -v /appliance/@author < <(dog --no-header $meta))"
if ! grep $mercurial_repository /etc/apt/sources.list > /dev/null 2>&1 ; then
        echo "deb http://$mercurial_repository ./" >> /etc/apt/sources.list
fi
apt-get update
apt-get install --force-yes -y mercurial=1.0.1-1+init1 mercurial-common=1.0.1-1+init1
cd /
if [ ! -f .hgignore ] ; then
        cat > /.hgignore <<'EOF'
syntax: glob
*~
.ccache

syntax: regexp
^var/backups
^var/cache
^var/log
^var/run
^var/spool
^var/tmp
^var/lib/mysql
^var/lock
^sys/
^dev/
^tmp/
^proc
EOF
fi
if [ ! -d .hg ] ; then
        hg init
        hg add
        hg commit -m 'initial'
fi
perl -pi -e 's/.*ACTIVE.*/ACTIVE=yes/' /etc/default/mercurial
perl -pi -e "s|.*URL=.*|URL=$url|" /etc/default/mercurial
/etc/init.d/mercurial start
if ! grep hgc /root/.bashrc ; then
        echo "alias hgc='/usr/bin/hg commit -u $author'" >> /root/.bashrc
fi
echo DONE
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class="tagglyTagging" macro="tagglyTagging"></div>
<div class='tagged' macro='tags'></div>
<div macro="hideWhen tiddler.tags.containsAny(['css','html','pre','systemConfig']) && !tiddler.text.match('{{'+'{')">
<div class='viewer' macro='view text wikified'></div>
</div>
<div macro="showWhen tiddler.tags.containsAny(['css','html','pre','systemConfig']) && !tiddler.text.match('{{'+'{')">
<div class='viewer'><pre macro='view text'></pre></div>
</div>
<div class='tagClear'></div>
<!--}}}-->
/***
|''Name:''|WebDavPlugin|
|''Description:''|Allows a TiddlyWiki to be saved to a WebDav server|
|''Author:''|Saq Imtiaz ( lewcid@gmail.com )|
|''Co-author:''|Loic Dachary|
|''Source:''|http://tw.lewcid.org/#WebDavPlugin|
|''Code Repository:''|http://tw.lewcid.org/svn/plugins|
|''Version:''|1.0|
|''Date:''|17/11/2007|
|''License:''|[[Creative Commons Attribution-ShareAlike 3.0 License|http://creativecommons.org/licenses/by-sa/3.0/]]|
|''~CoreVersion:''|2.2.3|

***/
// /%
//!BEGIN-PLUGIN-CODE
DAV = {
	run : function(type,u,data,cb,params,headers){
		var callback = function(status,params,responseText,url,xhr) {
			url = url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1);
			if(params.length){
				params.shift().apply(this,[status,params,responseText,url,xhr]);
			}
		};	
		params = params||[];
		params.unshift(cb);		
		var r = doHttp.apply(this,[type,u,data,null,null,null,callback,params,headers]);
		if (typeof r == "string")
			alert(r);
		return r;
	},
	
	get : function(url,cb,params){
		return DAV.run("GET",url,null,cb,params,null);
	},

	put : function(url,cb,params,data) {
		return DAV.run("PUT",url,data,cb,params,null);
	},

	move : function(url,cb,params,destination) {
		return DAV.run("MOVE",url,null,cb,params,{"Destination":destination,"Overwrite":"T"});
	}, 

	copy : function(url,cb,params,destination) {
		return DAV.run("COPY",url,null,cb,params,{"Destination":destination,"Overwrite":"T","Depth":0});
	},
	
	propfind : function(url,cb,params,prop,depth){	// !!!
		var xml = '<?xml version="1.0" encoding="UTF-8" ?>' +
			'<D:propfind xmlns:D="DAV:">' +
			'<D:prop>'+
			'<D:'+prop+'/>'+
			'</D:prop>'+
			'</D:propfind>';
		return DAV.run("PROPFIND",url,xml,cb,params,{"Content-type":"text/xml","Depth":depth?depth:0});
	},
	
	makeDir : function(url,cb,params){
		return DAV.run("MKCOL",url,null,cb,params,null);
	},

	options : function(url,cb,params){
		return DAV.run("OPTIONS",url,null,cb,params,null);
	},
	
	safeput : function(url,cb,params,data){
		firstcb = function(status,p,responseText,u,xhr){
			if(status)
				DAV.move(u,cb,p,u.replace("-davsavingtemp",""));
			else
				cb.apply(firstcb,arguments);
		};
		return DAV.put(url+"-davsavingtemp",firstcb,params,data);
	}	
};

config.DavSaver = {
	defaultFileName : 'index.html',
	messages : {
		startSaveMessage : 'saving to server...',
		endSaveMessage : 'TiddlyWiki successfuly saved to server',
		overwriteNewerPrompt : 'The remote file has changed since you last loaded or saved it.\nDo you wish to overwrite it?',
		getModDateError : "Could not get last modified date",
		raceError: "Save failed because the remote file is newer than the one you are trying to save"
	},
	errors:{
		raceconflict : 'The save failed because your file is out of date',
		getlastmodified : 'The save was aborted because the last modified date of the file could not be retrieved',
		davenabled : 'The server does not support WebDav',
		saverss : 'There was an error saving the rss file, the save was aborted',
		saveempty: 'There was an error saving the empty file, the save was aborted',
		savemain : 'Save failed! There was an error saving the main TW file',
		savebackup: 'Save failed! There was an error creating a backup file',
		makebackupdir: 'Save failed! The backup directory could not be created'		
	},
	timestamp: new Date().toGMTString(),
	orig_saveChanges: saveChanges,
	saver : null
};

DavSaver = function(){
	
	this.Q = [];	

	this.reset = function(){
		config.DavSaver.saver = null;
	};
	this.runQ = function(){
		if(this.Q.length){
			this.Q.shift().apply(this,arguments);
		}
		else
			this.reset();
	};
	this.posDiv = null;
	this.original = null;
	
	this.getOriginalPath = function(){
		var p = document.location.toString();
		p = convertUriToUTF8(p,config.options.txtFileSystemCharSet);
		var argPos = p.indexOf("?");
		if(argPos != -1)
			p = p.substr(0,argPos);
		var hashPos = p.indexOf("#");
		if(hashPos != -1)
			p = p.substr(0,hashPos);		
		if (p.charAt(p.length-1) == "/")
			p = p + config.DavSaver.defaultFileName;
		return p;
	};
	
	this.originalPath = this.getOriginalPath();
	this.backupPath = null;
	this.emptyPath = null;
	this.rssPath = null;
	this.throwError = function(er){
		clearMessage();
		this.reset();
		alert(config.DavSaver.errors[er]);   //clear message, reset and delete
	};
};

DavSaver.prototype.getOriginal = function(){
	var	callback = function(status,params,original,url,xhr) {
		var that = params[0];
		if(status){
			var p = that.posDiv = locateStoreArea(original);
			if(!p || (p[0] == -1) || (p[1] == -1)) {
				alert(config.messages.invalidFileError.format([url]));
				return;
			}
			that.original = original;
			that.runQ();
		}
		else
			that.throwError('getOriginal');
	};
	
	DAV.get(this.originalPath,callback,[this]);	
};

DavSaver.prototype.checkRace = function(){
	var callback = function(status,params,responseText,url,xhr){
		var that = params[0];
		if(status){
			var lastmod = responseText.match(/<(\w*?):getlastmodified>(.*?)<\/\1:getlastmodified>/)[2];
			if(Date.parse(lastmod) > Date.parse(config.DavSaver.timestamp)){
				if (confirm(config.DavSaver.messages.overwriteNewerPrompt))
					that.runQ();
				else
					that.throwError('raceconflict');
			}
			else	
				that.runQ();
		}
		else
			that.throwError('getlastmodified');
	};
	
	DAV.propfind(this.originalPath,callback,[this],"getlastmodified",0);	
};

DavSaver.prototype.isDavEnabled = function(){
	var callback = function(status,params,responseText,url,xhr){
		that = params[0];
		if(status && !! xhr.getResponseHeader("DAV")){
			that.runQ();
			}
		else
			that.throwError('davenabled');
	};
	DAV.options(this.originalPath,callback,[this]);		
};

DavSaver.prototype.saveRss = function(){
	var callback = function(status,params,responseText,url,xhr){
		var that = params[0];
		if(status){
			displayMessage(config.messages.rssSaved,that.rssPath);
			that.runQ();
		}
		else
			that.throwError('saverss');
	};
	var u = this.originalPath;
	var rssPath = this.rssPath = u.substr(0,u.lastIndexOf(".")) + ".xml";
	DAV.safeput(rssPath,callback,[this],convertUnicodeToUTF8(generateRss()));	
};

DavSaver.prototype.saveEmpty = function(){
	var callback = function(status,params,responseText,url,xhr){
		var that = params[0];
		if(status){
			displayMessage(config.messages.emptySaved,that.emptyPath);
			that.runQ();
		}
		else
			that.throwError('saveempty');
	};
	var u = this.originalPath;
	var emptyPath,p;
	if((p = u.lastIndexOf("/")) != -1)
		emptyPath = u.substr(0,p) + "/empty.html";
	else
		emptyPath = u + ".empty.html";
	this.emptyPath = emptyPath;
	var empty = this.original.substr(0,this.posDiv[0] + startSaveArea.length) + this.original.substr(this.posDiv[1]);
	DAV.safeput(emptyPath,callback,[this],empty);		
};

DavSaver.prototype.saveMain = function(){
	var callback = function(status,params,responseText,url,xhr){
		var that = params[0];
		if(status){
			config.DavSaver.timestamp = xhr.getResponseHeader('Date');
			displayMessage(config.messages.mainSaved,that.originalPath);
			store.setDirty(false);
			that.runQ();
		}
		else
			that.throwError('savemain');		
	};
	var revised = updateOriginal(this.original,this.posDiv);
	DAV.safeput(this.originalPath,callback,[this],revised);
};

DavSaver.prototype.saveBackup = function(){	
	var callback = function(status,params,responseText,url,xhr){
		var that = params[0];
		if(status){
			clearMessage();
			displayMessage(config.messages.backupSaved,that.backupPath);
			that.runQ();
		}
		else
			that.throwError('savebackup');
	};
			
	var backupPath = this.backupPath = getBackupPath(this.originalPath);
	DAV.copy(this.originalPath,callback,[this],this.backupPath);		
};

DavSaver.prototype.makeBackupDir = function(){
	var callback = function(status,params,responseText,url,xhr){
		var that = params[0];
		if(status)
			that.runQ();
		else
			that.throwError('makebackupdir');
	};
	var u = getBackupPath(this.originalPath);
	var backupDirPath = u.substr(0,u.lastIndexOf("/"));
	DAV.makeDir(backupDirPath,callback,[this]); 
};

DavSaver.prototype.save = function(onlyIfDirty,tiddlers){
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	displayMessage(config.DavSaver.messages.startSaveMessage);
	var Q = this.Q =[];
	Q.push(this.isDavEnabled);
	Q.push(this.getOriginal);
	Q.push(this.checkRace);
	if (config.options.chkSaveBackups){
		if (config.options.txtBackupFolder!='')
			Q.push(this.makeBackupDir);
		Q.push(this.saveBackup);
	}
	Q.push(this.saveMain);
	if (config.options.chkGenerateAnRssFeed)
		Q.push(this.saveRss);
	if (config.options.chkSaveEmptyTemplate)
		Q.push(this.saveEmpty);
	//Q.push(this.reset);
	this.runQ();
};

window.saveChanges = function(onlyIfDirty,tiddlers)
{	
	var c = config.DavSaver;
	if (document.location.protocol.toString() == "http:"){
		var saver = c.saver = new DavSaver();
		saver.save(onlyIfDirty,tiddlers);		
	}
	else
		return c.orig_saveChanges(onlyIfDirty,tiddlers);
};
//!END-PLUGIN-CODE
// %/
* When parts of the universe are in different locations, DNS queries go thru DNS out of control with cache policies that can vary. However, when setting up a new domain name and the monitor (nagios) is not in the same geographical location, it is unpractical to wait for the cache to update. The solution is to instruct the DNS serving a given host to directly ask the primary DNS for a domain on which control is guaranteed. For instance, if pokersource.info is under control, this can be added to named.conf:
{{{
zone "pokersource.info."{
   type forward ;
   forward only ;
   forwarders {
       88.191.250.41 ;
   } ;
};
}}}
* {{{/etc/init.d/bind9 restart}}} because reload is not enough for this kind of change
{{{
qemu-img create -b baseimage.qcow -f qcow workingcopy.qcow
qemu workingcopy.qcow
}}}
* workingcopy.qcow only store the delta from baseimage.qcow
* can be easily automated
* an extra step could be to allow credentials upload to the newly created appliance
* use {{{/usr/sbin/qemu-make-debian-root}}} with {{{rsync}}}
** qemu-make-debian-root is buggy
*** https://bugs.launchpad.net/ubuntu/+source/qemu/+bug/63429
* http://www.rot13.org/~dpavlin/debian-amd64.html
* figure out how rpath do it http://wiki.rpath.com/wiki/rBuilder:Test_Images_with_QEMU
* look at livecd generation system
* boot a livecd and install grub and kernel on the image
{{{
18:56 <proppy`> themill: did you manage to actually boot this kind of
                image ?
18:57 <themill> proppy`: you could boot off a ISO image of a live cd
                for example with the disk image being added as an
                extra disk.
18:57 <proppy`> themill: oh ok
18:57 *** seemawn JOIN
18:57 <themill> proppy`: then chroot into the extra disk image and
                then "install" the kernel and grub etc
18:57 <proppy`> themill: i see
}}}
* look at kiwi http://kiwi.berlios.de/
The OpenSuSE KIWI Image System provides a complete operating system image solution for Linux supported hardware platforms as well as for virtualisation systems like Xen Qemu or VMware. The KIWI architecture was designed as a two level system. The first stage, based on a valid software package source, creates a so called physical extend according to the provided image description. The second stage creates from a required physical extend an operating system image. The result of the second stage is called a logical extend or short an image. 
{{{
19:23 *** proppy` JOIN
19:23 *** TOPIC kiwi rocks :-) Current version: 1.43 -
                http://ftp.opensuse.org/pub/opensuse/repositories/openSUSE:/Tools
                (schaefi on Mon Jul  9 17:47:58 2007)
19:23 *** NAMES proppy` fxrsliberty schaefi SLEducator merriam__
                captain_magnus snorp apokryphos kbunnell  
19:23 <proppy`> hi
19:24 <snorp> hey
19:25 <proppy`> can i use kiwi to turn a chroot into a qemu img ?
19:25 *** glunardi JOIN
19:25 <snorp> proppy`: yes
19:26 <snorp> that is easy though
19:26 <snorp> you don't need kiwi for that
19:26 <snorp> (I don't think)
19:27 <proppy`> ho i think i was kiwi purpose
19:27 <proppy`> actually even if it seems easy i've not managed to do
                it :)
19:27 <proppy`> loop mounting the img and rsync doesn't really build a
                bootable image
19:28 <snorp> oh, you want to boot it
19:28 <snorp> yeah, kiwi can do that
19:28 <proppy`> i've installed kiwi packages
19:29 <proppy`> from kiwi xubuntu repository
19:29 <snorp> hmm
19:29 <snorp> does kiwi work on ubuntu?
19:29 <proppy`> (which seems broken btw i had to install package by
                hand)
19:29 <proppy`> (dpkg)
19:29 <snorp> I don't think we have stuff for booting ubuntu machines
19:29 <proppy`>
                http://ftp.opensuse.org/pub/opensuse/repositories/openSUSE:/Tools/xUbuntu_7.04/
19:29 <proppy`> there is a repository
19:29 <proppy`> with osc and build .deb
19:30 <snorp> yeah
19:30 <snorp> but I don't think kiwi has code in it yet for generating
              ubuntu chroots, etc
19:30 <proppy`> i've already generated the chroot
19:30 <proppy`> its hand cooked
19:30 <proppy`> i only search for a way to turn it into a bootable
                image
19:30 <snorp> but it won't have the right stuff for kiwi to use when
              booting
19:30 <proppy`> which i believe is not really distro dependant ?
19:31 <snorp> well it sort of is
19:31 <snorp> boot scripts/initrd vary by distro
19:32 <proppy`> snorp: what are the debian/ubuntu packages for ?
19:32 <snorp> proppy`: well you can use it to generate a suse image :)
19:32 <snorp> from an ubuntu machine
19:33 <proppy`> it can generate a suse image from an existing chroot
                ?:)
19:33 <proppy`> or its input is rather a suse package
19:33 <proppy`> ?
19:33 <snorp> input is suse packages
19:33 <snorp> output is suse image
19:33 <proppy`> ok
19:35 *** proppy` NICK proppy
19:39 <proppy> thanks for the explanation:)
> 
}}}
* in interfaces
* do not autocreate from libvrit
The fam2rss software appliance contains a single spec file. It can be moved to a directory at http://specs.dachary.org/. External links to the spec file can be preserved. RSS feeds need not be changed, except if refering to the obsoleted software appliance with a non routable IP. External links to the corresponding hg repository are redirected to a unique non existent URLs. 
* copy the content over to http://specs.dachary.org/fam2rss/
** in /etc/fstab there is
{{{
http://fam2rss.dachary.org /fam2rss.dachary.org davfs noauto,user,exec 0 0
http://specs.dachary.org /specs.dachary.org davfs noauto,user,exec 0 0
}}}
** copy gently because DAV has issues (see unrelsolved issues in http://garden.dachary.org/)
{{{
cd /fam2rss.dachary.org/
mkdir /specs.dachary.org/fam2rss
cp -a index.html scrapbook /specs.dachary.org/fam2rss/
}}}
* kill the apache proxy pass and redirect it to the new location /etc/apache2/sites-available/fam2rss.dachary.org as shown in http://hg.dachary.org/file/3b64f7ee7716/etc/apache2/sites-available/fam2rss.dachary.org leading to 
{{{
<VirtualHost *>
    ServerName          fam2rss.dachary.org
    RedirectMatch       permanent ^/(.*)        http://specs.dachary.org/fam2rss/$1
</VirtualHost>

<VirtualHost *>
    ServerName          hg.fam2rss.dachary.org
    RedirectMatch       permanent .*    http://specs.dachary.org/fam2rss/#obsolete-hg
</VirtualHost>
}}}
* backup the software appliance and remove it
{{{
vserver fam2rss stop
tar -zcvf var/lib/vservers/specs/home/www/fam2rss/fam2rss.dachar.org-2007-06-07.tar.gz etc/vservers/fam2rss var/lib/vservers/fam2rss 
rm -fr etc/vservers/fam2rss var/lib/vservers/fam2rss
}}}
* free the local IP and name in the local DNS as found at http://hg.pecho.fsffrance.org/rev/4fcf6125f1d1
{{{
--- a/etc/bind/db.192.168	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/db.192.168	Thu Jun 07 11:34:33 2007 +0200
@@ -4,7 +4,7 @@
 ;
 $TTL	604800
 @	IN	SOA	localhost. root.localhost. (
-                        2007053002      ; serial number
+                        2007060700      ; serial number
 			 604800		; Refresh
 			  86400		; Retry
 			2419200		; Expire
@@ -46,7 +46,7 @@ 34.50	IN	PTR	poker-network-1-0-37.pokers
 34.50	IN	PTR	poker-network-1-0-37.pokersource.fsf.tld.
 35.50	IN	PTR	openscenegraph.dachary.fsf.tld.
 36.50	IN	PTR	jacques.dachary.fsf.tld.
-37.50	IN	PTR	fam2rss.dachary.fsf.tld.
+37.50	IN	PTR	available-37.fsf.tld.
 38.50	IN	PTR	garden.dachary.fsf.tld.
 39.50	IN	PTR	poker-network-1-1-0.pokersource.fsf.tld.
 40.50	IN	PTR	specs.dachary.fsf.tld.

--- a/etc/bind/db.fsf	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/db.fsf	Thu Jun 07 11:34:33 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN fsf.tld.
 @                       IN      SOA             ns hostmaster (
-                                2007053001      ; serial number
+                                2007060700      ; serial number
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
@@ -51,7 +51,7 @@ poker-network-1-0-37.pokersource	IN     
 poker-network-1-0-37.pokersource	IN      A	192.168.50.34
 openscenegraph.dachary			IN      A	192.168.50.35
 jacques.dachary				IN      A	192.168.50.36
-fam2rss.dachary				IN      A	192.168.50.37
+available-37				IN      A	192.168.50.37
 garden.dachary				IN      A	192.168.50.38
 poker-network-1-1-0.pokersource		IN      A	192.168.50.39
 specs.dachary				IN      A	192.168.50.40

--- a/etc/bind/named.conf	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/named.conf	Thu Jun 07 11:34:33 2007 +0200
@@ -29,7 +29,7 @@ view "fsffrance.org" {
 };
 
 view "dachary.org" {
-  match-clients { 192.168.50.13; 192.168.50.14; 192.168.50.17; 192.168.50.19; 192.168.50.20; 192.168.50.22; 192.168.50.23; 192.168.50.27; 192.168.50.28; 192.168.50.33; 192.168.50.35; 192.168.50.37; 192.168.50.38; 192.168.50.40; 192.168.50.41; 192.168.50.43; 88.191.250.36; };
+  match-clients { 192.168.50.13; 192.168.50.14; 192.168.50.17; 192.168.50.19; 192.168.50.20; 192.168.50.22; 192.168.50.23; 192.168.50.27; 192.168.50.28; 192.168.50.33; 192.168.50.35; 192.168.50.38; 192.168.50.40; 192.168.50.41; 192.168.50.43; 88.191.250.36; };
   zone "conf.tld" {
     type master;
     file "/etc/bind/views/dachary.org.view";

--- a/etc/bind/views/dachary.org.view	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/views/dachary.org.view	Thu Jun 07 11:34:33 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN conf.tld.
 @                       IN      SOA             ns hostmaster (
-                                2007053005      ; serial number
+                                2007060700      ; serial number
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
@@ -33,7 +33,6 @@ bellinux		IN	CNAME	bellinux.dachary.fsf.
 bellinux		IN	CNAME	bellinux.dachary.fsf.tld.
 openscenegraph		IN	CNAME	openscenegraph.dachary.fsf.tld.
 jacques			IN	CNAME	jacques.dachary.fsf.tld.
-fam2rss			IN	CNAME	fam2rss.dachary.fsf.tld.
 garden			IN	CNAME	garden.dachary.fsf.tld.
 specs			IN	CNAME	specs.dachary.fsf.tld.
 versavant		IN	CNAME	versavant.dachary.fsf.tld.

}}}
* remove firewall redirections to fam2rss.dachary.org as found at http://hg.pecho.fsffrance.org/rev/929ee5ca9e4c
{{{
--- a/etc/shorewall/params	Thu Jun 07 11:34:33 2007 +0200
+++ b/etc/shorewall/params	Thu Jun 07 11:40:25 2007 +0200
@@ -68,7 +68,6 @@ VSRV_DUVAL=192.168.50.25
 VSRV_DUVAL=192.168.50.25
 VSRV_PACKAGING_FARM=192.168.50.20
 VSRV_JACQUES=192.168.50.36
-VSRV_FAM2RSS=192.168.50.37
 VSRV_GARDEN=192.168.50.38
 VSRV_OPENSCENEGRAPH=192.168.50.35
 VSRV_URLCONVERSION=192.168.50.23
@@ -79,7 +78,6 @@ DACHARY_SSH_DUVAL=5022
 DACHARY_SSH_DUVAL=5022
 DACHARY_SSH_PACKAGING_FARM=6022
 DACHARY_SSH_JACQUES=7022
-DACHARY_SSH_FAM2RSS=8022
 DACHARY_SSH_GARDEN=9022
 DACHARY_SSH_OPENSCENEGRAPH=10022
 DACHARY_RSYNC_OPENSCENEGRAPH=10873

--- a/etc/shorewall/rules	Thu Jun 07 11:34:33 2007 +0200
+++ b/etc/shorewall/rules	Thu Jun 07 11:40:25 2007 +0200
@@ -449,7 +449,6 @@ DNAT		net             tld:$VSRV_ECOLE:22
 DNAT		net             tld:$VSRV_ECOLE:22      tcp     ${DACHARY_SSH_ECOLE:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_DUVAL:22      tcp     ${DACHARY_SSH_DUVAL:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_JACQUES:22      tcp     ${DACHARY_SSH_JACQUES:-.}     -       ${DACHARY:-.} 
-DNAT		net             tld:$VSRV_FAM2RSS:22      tcp     ${DACHARY_SSH_FAM2RSS:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_GARDEN:22      tcp     ${DACHARY_SSH_GARDEN:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_OPENSCENEGRAPH:22      tcp     ${DACHARY_SSH_OPENSCENEGRAPH:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_OPENSCENEGRAPH:873      tcp     ${DACHARY_RSYNC_OPENSCENEGRAPH:-.}     -       ${DACHARY:-.} 
}}}
http://www.cs.toronto.edu/~andreslc/xen-gl/
poker-network-1-2-0:/# author=loic@dachary.org ; app=munin-node ; apt-get install -y --force\
-yes $app && hg addremove && hg commit -u $author -m "apt-get install $app"
*** output flushed ***
poker-network-1-2-0:/# perl -pi -e 's/^allow.*/allow ^.*\$/' /etc/munin/munin-node.conf
poker-network-1-2-0:/# /etc/init.d/munin-node restart
Stopping Munin-Node: done.
Starting Munin-Node: done.
poker-network-1-2-0:/#
<<<
No tricks : plain simple shorewall configuration. The laptop has a wifi connection on eth1 and a ~RJ45 cable on eth0.
///etc/shorewall/interfaces//
{{{
###############################################################################
#ZONE	INTERFACE	BROADCAST	OPTIONS
net     eth0                 detect          routefilter,dhcp,tcpflags,nosmurfs
net     eth1                 detect          routefilter,dhcp,tcpflags,nosmurfs
my	eth0.2		     detect	     dhcp
}}}
///etc/shorewall/masq//
{{{
###############################################################################
#INTERFACE		SUBNET		ADDRESS		PROTO	PORT(S)	IPSEC
eth1			eth0.2
eth0			eth0.2
}}}
///etc/shorewall/params//
{{{
VOD=192.168.50.11
}}}
///etc/shorewall/policy//
{{{
###############################################################################
#SOURCE		DEST		POLICY		LOG		LIMIT:BURST
#						LEVEL
$FW             net             ACCEPT
net             $FW             DROP            info
# my has no filtering
my              all             ACCEPT
all             my              ACCEPT
# The FOLLOWING POLICY MUST BE LAST
all             all             REJECT          info
}}}
///etc/shorewall/rules//
{{{
###############################################################################
#ACTION	SOURCE		DEST		PROTO	DEST	SOURCE		ORIGINAL	RATE		USER/
#						PORT(S)	PORT(S)		DEST		LIMIT		GROUP
#SECTION ESTABLISHED
#SECTION RELATED
SECTION NEW
DNAT:debug	net		my:${VOD:-.} tcp	37000:38000
ACCEPT            net             $FW	tcp	37000:38000
SSH/ACCEPT    net             $FW
HTTP/ACCEPT  net             $FW
ACCEPT            net             $FW	tcp	24800
}}}
Note the {{{${VOD:-.}}}} instead of a simple {{{$VOD}}}. The rationale is that you want to evaluate all the variables using the dot as a default. A typo in the variable name turns a variable into a space which leads to very confusing error messages or even no error message at all. A default value of dot or any other string gives much more readable error messages.
///etc/shorewall/zones
{{{
###############################################################################
#ZONE	TYPE		OPTIONS		IN			OUT
#					OPTIONS			OPTIONS
fw	firewall
my	-
net	ipv4
}}}
<<<
* define the check_ssh_port command
{{{
cat > /etc/nagios2/conf.d/check_ssh_port.cfg <<EOF
define command{
        command_name    check_ssh_port
        command_line    /usr/lib/nagios/plugins/check_ssh -p $ARG1$ $HOSTADDRESS$
        }
EOF
}}}
* monitor the ssh server running on a given port 
{{{
port=15022 ; name=markerclock ; domain=dachary.org
cat >> $domain <<EOF
define service {
  host_name     $name
  service_description $name ssh
  check_command check_ssh_port!$port
  use           generic-service
  }
}}}
* Documentation patch http://sourceforge.net/tracker/index.php?func=detail&aid=1721843&group_id=29880&atid=397599
* Create the test before running the service
* Activate external commands to force the check
{{{
--- a/etc/nagios2/nagios.cfg	Thu May 17 15:01:42 2007 +0200
+++ b/etc/nagios2/nagios.cfg	Thu May 17 16:17:28 2007 +0200
@@ -127,7 +127,7 @@ nagios_group=nagios
 # you will have to enable this.  Setting this value to 0 disables command
 # checking (the default), other values enable it.
 
-check_external_commands=0
+check_external_commands=1

}}}
* Give permissions to www-data
{{{
chmod g+rwxs /var/lib/nagios2/rw 
chgrp -R www-data  /var/lib/nagios2
}}}
* {{{apt-get install nagios-plugins-standard}}}
* Use plugin from the command line on the machine running the service after installing {{{apt-get install nagios-plugins-standard}}} which does not require to install a complete nagios
* Edit /etc/passwd to give shell to nagios user and add the key of the nagios machine that will be probing the service in //.ssh/authorized_keys//. Make sure the access is IP limited because you don't want to deal with nagios security holes.
{{{
from="*.mekensleep.com" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvg8CgXpHpLC5L/335GObQk/JSwdJBt5p118+f9b0YwOajHbxcThPDQatg/urnaR9HFmrj03DIvCBYylaoAPnC59lEmv/nUW4U558EFGyvECldudbmscHYudGAkKs4+ctfHTTVUTNv8JyEiZnII5bWn8uApUbQCojfGHfv11lQrPmFj88GcXwLdx+TD3DoEqdMrnKQIjpIYDAEhat8sy8eS2ZFVzwdz20iOVe8+aHkKzU6f85jTg7uT3Z2z/gwz/6tvh6r5UebUPiJVmmuZ6sIG35LjFUrCWkve/tYy6FWYUP40xP5VRH4nw5fji1AQjJyHcSR80B7xn7W7UwVHbVnQ== root@mon2.dmz.free.tld
}}}
* On the nagios host, create a ssh key without password that will be exclusively used for querying nagios
* On the nagios host create a new service as follows:
{{{
define command{
        command_name    money_counter
        command_line    /usr/lib/nagios/plugins/check_by_ssh -i /home/nagios/.ssh/id_rsa -C '/usr/lib/nagios/plugins/check_mysql_query -q s\
elect\ count\(serial\)\ from\ counter -u nagios -d pokernetwork -H localhost -c 0:0' -l nagios -H gw.host.xs4all.mekensleep.net -p 42002 -t\
 20
        }
define service {
  host_name     poker-db-03
  service_description money:counter
  check_command money_counter
  use           generic-service
}
}}}
# cmd poker-network-1-2-0 pokersource.info 380 pokersource fsf tld [ 19380 [ 10380 ]]
set -e
name="$1"
domain="$2"
service="$3"
realm="$4"
vserver_realm="$5"
zone="$6"
port="$7"
range_port="$8"
ip=$(getent hosts $name.$domain. | cut -f1 -d' ')
test "$ip"
cd /etc/shorewall/$ip
if [ ! -d $name ] ; then
    mkdir $name
    port_range=$(ls ports | head -1)
    echo $port_range > $name/port
    rm ports/$port_range
fi

if [ -z "$port" ] ; then
    if getent services $service > /dev/null ; then
        port=$(expr "$(getent services $service)" : '.* \([0-9][0-9]*\)/')
    else
        port=$service
    fi
    test "$port"
fi
if [ -z "$range_port" ] ; then
    range_port=$(expr $(cat $name/port) + $port)
    test "$range_port"
fi
local_ip=$(getent hosts $name.$realm.$vserver_realm.tld | cut -f1 -d' ')
test "$local_ip"
if [ ! -f $name/local_dmz.rules ] ; then
    echo "ACCEPT net \$FW:$local_ip" > $name/local_dmz.rules
fi
echo "DNAT net $zone:$local_ip:$port tcp $range_port - $ip" > $name/$service.rules
make -f ../collect.mk

{{{
pecho:/etc/shorewall# ssh=15022 ; name=MARKERCLOCK ; ip=192.168.50.254
pecho:/etc/shorewall# echo "VSRV_$name=$ip" >> params
pecho:/etc/shorewall# echo "DACHARY_SSH_$name=$ssh" >> params
pecho:/etc/shorewall# perl -pi -e 's/^#LAST LINE.*//;' params
pecho:/etc/shorewall# echo '#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE' >> params
pecho:/etc/shorewall# perl -pi -e 's/#PATCH_DACHARY/DNAT\t\tnet\ttld:\$VSRV_'$name':22\ttcp\t\${DACHA\
RY_SSH_'$name':-.}\t-\t\${DACHARY:-.}\n#PATCH_DACHARY/' rules
pecho:/etc/shorewall#
pecho:/etc/shorewall# perl -pi -e 's/#PATCH_DACHARY/ACCEPT\tnet\t\$FW:\${VSRV_'$name':-.}\n#PATCH_DAC\
HARY/' rules
pecho:/etc/shorewall# shorewall restart
*** output flushed ***
pecho:/etc/shorewall# # missing check
pecho:/etc/shorewall# hg commit -m "add $name ssh port $ssh to shorewall" /etc/shorewall
No username found, using 'root@pecho.fsffrance.org' instead
}}}
auto peth0
allow-hotplug peth0
iface peth0 inet static
      pre-up    ip link set eth0 name peth0
      address   172.24.201.11
      netmask   255.255.0.0
      post-up   ifup eth0

iface eth0 inet static
      address   172.24.201.10
      netmask   255.255.0.0
      gateway   172.24.0.13
      bridge_ports peth0
      bridge_stp off
      bridge_maxwait 5
(03:23:48 PM) The topic for #kvm is:  KVM wiki website is http://www.linux-kvm.org - try status and faq pages, no really, read them! || you can also check the qemu manual at http://www.nongnu.org/qemu/user-doc.html || don't paste on chan, use http://rafb.net/paste instead || libvirt/virt-manager support is #virt on OFTC servers
(03:24:02 PM) balbir left the room (quit: Read error: 110 (Connection timed out)).
(03:24:54 PM) dachary: Hi. I'm having issues with the entropy in a kvm : there is not enough of it in /dev/random. Is there a way I can say : plug the kvm random to the host urandom or something ? 
(03:25:02 PM) jieryn-w: i'm downgrading to kvm-83 to try that
(03:26:38 PM) rharper left the room (quit: pratchett.freenode.net irc.freenode.net).
(03:26:38 PM) Gilou left the room (quit: pratchett.freenode.net irc.freenode.net).
(03:26:38 PM) awilliam left the room (quit: pratchett.freenode.net irc.freenode.net).
(03:26:38 PM) amitshah left the room (quit: pratchett.freenode.net irc.freenode.net).
(03:26:38 PM) cdub left the room (quit: pratchett.freenode.net irc.freenode.net).
(03:26:38 PM) _LM__ left the room (quit: pratchett.freenode.net irc.freenode.net).
(03:26:38 PM) basilarchia left the room (quit: pratchett.freenode.net irc.freenode.net).
(03:26:43 PM) rharper [n=rharper@r74-193-64-230.pfvlcmta01.grtntx.tl.dh.suddenlink.net] entered the room.
(03:26:43 PM) Gilou [n=me@unaffiliated/gilou] entered the room.
(03:26:43 PM) awilliam [n=awilliam@c-67-174-104-198.hsd1.co.comcast.net] entered the room.
(03:26:43 PM) cdub [n=chrisw@sous-sol.org] entered the room.
(03:26:43 PM) basilarchia [n=basilarc@69.38.218.221] entered the room.
(03:26:43 PM) amitshah [n=amit@unaffiliated/amitshah] entered the room.
(03:26:43 PM) _LM__ [i=lm@newtrillian.jogback.se] entered the room.
(03:28:49 PM) jieryn-w: hm, modinfo kvm doesn't tell me the version
(03:31:15 PM) cdub left the room (quit: Remote closed the connection).
(03:36:50 PM) mhiramat [n=mhiramat@nat/redhat/x-c22cd00f54ed0d5d] entered the room.
(03:40:41 PM) agraf__: jieryn-w: does it work if you use -encodings zlib?
(03:42:00 PM) pkt: dachary: I think there was a virtio device for doing that
(03:42:14 PM) pkt: virtio-rng ?
(03:42:22 PM) Sho_ [n=EHS1@kde/hein] entered the room.
(03:42:40 PM) mhiramat_ [n=mhiramat@pool-173-48-242-171.bstnma.fios.verizon.net] entered the room.
(03:42:41 PM) aliguori: dachary, out of curiousity, what led you to this conclusion?
(03:42:54 PM) aliguori: i haven't implemented the virtio entropy device because i never thought anyone would want it
(03:43:13 PM) mjt: but there is virtio_ring, isn't it?
(03:43:30 PM) mjt: or rng
(03:43:31 PM) boto [n=ehabkost@189.26.39.120.dynamic.adsl.gvt.net.br] entered the room.
(03:43:32 PM) pkt: virtio_ring is a different thing
(03:43:52 PM) dachary: aliguori: a test suite uses a lot of entropy 
(03:44:01 PM) mjt: there was something about virtio random number generator in config
(03:44:16 PM) dachary: and it blocks for a lot time in the VM because there is no activity and therefore no entropy
(03:44:23 PM) dachary: does this make sense ? 
(03:44:26 PM) pkt: dachary: can't the testsuite run off /dev/urandom instead?
(03:45:01 PM) pkt: you could also very easily hack your kernel to make your network card an additional source of entropy
(03:45:06 PM) dachary: of course, there always is the option of fixing the software to fit the machine ;-) 
(03:45:21 PM) dachary: it eventually completes, it's not a blocker
(03:45:27 PM) dachary: only it takes a very long time
(03:45:36 PM) jieryn-w: agraf__: i downgraded to kvm-83 (from 85) and everything is working peachy
(03:45:45 PM) pkt: well, blocking for a lot of time does sound like a problem
(03:45:49 PM) dachary: parts of the tests are switching from /dev/random to /dev/urandom
(03:45:50 PM) mhiramat left the room (quit: Read error: 60 (Operation timed out)).
(03:46:29 PM) pkt: setting the network card as an additional source of entropy has worked for me in some low-security cases
(03:46:44 PM) dachary: pkt: I sense you're trying to convince me that I have no problem ;-)
(03:47:09 PM) pkt: eh? I thought I was proposing solutions :)
(03:47:18 PM) dachary: I agree to the extent that it's just an inconvenience, not a problem.
(03:47:50 PM) dachary: I like the tests to go as fast as possible but it's not blocking anything if it takes longer.
(03:48:13 PM) pkt: I proposed /dev/urandom, virtio-rng and getting more entropy from sound/network
(03:48:23 PM) pkt: or a combination :)
(03:48:35 PM) dachary: :-)
(03:48:43 PM) bstein [n=bstein@66.187.234.199] entered the room.
(03:48:47 PM) dachary: I'm gratefuly honestly. 
(03:48:58 PM) mhiramat [n=mhiramat@nat/redhat/x-e7a2cd5aaa834f34] entered the room.
(03:49:02 PM) dachary: virtio-rng exists ? 
(03:49:14 PM) awilliam left the room (quit: "Leaving").
(03:49:55 PM) hollisb [n=hollisb@63.246.169.171] entered the room.
(03:50:25 PM) pkt: hmm, I don't see it in the kernel sources, but I thought it did exist
(03:50:32 PM) pkt: perhaps it is queued for 2.6.30
(03:50:46 PM) pkt: drivers/char/hw_random/virtio-rng.c
(03:51:17 PM) dachary: good to know :-)
(03:51:17 PM) pkt: it is there after all :)
(03:51:42 PM) dachary: I'll just passively wait for it to show then. 
(03:52:13 PM) pkt: it should be there already, I just made a small mistake in my "find" command :)
(03:52:33 PM) pkt: in 2.6.29.1
(03:53:48 PM) qwe [n=qwe@86.57.137.7] entered the room.
(03:53:53 PM) sendro [n=sendro@124.189.100.200] entered the room.
(03:54:21 PM) damjan: is kvm-84 build-able with gcc-4.3 ?
(03:55:04 PM) pkt: why shouldn't it be?
(03:55:47 PM) damjan: older version required gcc-3.3
(03:56:55 PM) pkt: well, ever since qemu switched away from its gcc-codegen hacks to its own code generator (tcg), modern versions of gcc are ok
(03:56:56 PM) sendro: im running virt-manager with X11 forwarding through ssh .. how do i get to the monitor
(03:57:23 PM) sendro: i want to migrate the machine to other node.. ctrl+alt+2 dosnt work
(03:57:24 PM) damjan: pkt: yes, but when was that added to the kvm user-space fork?
(03:58:05 PM) pkt: I think I 've built kvm-84 with gcc-4.3 but I 'm not 100% sure
(03:58:11 PM) damjan: actually I'll build -85 .. its based on qemu 0.10 so it should work
(03:58:31 PM) pkt: yeah, for that I 'm 100% certain :)
(03:58:48 PM) pkt: but most likely -84 is fine too
(03:59:04 PM) edwin [n=edwin@79.114.96.229] entered the room.
(03:59:30 PM) awilliam [n=awilliam@15.195.201.88] entered the room.
(03:59:39 PM) agraf__: damjan: around kvm-70 IIRC
(03:59:44 PM) agraf__: damjan: maybe even before that
(04:00:09 PM) cynicismic left the room (quit: "leaving").
(04:00:13 PM) towo^work left the room (quit: "*Patsch* Feierabend").
(04:00:34 PM) sendro: umm, you know what i mean by monitor.. the console for kvm where u can use the migrate commands
(04:00:34 PM) damjan: hm.. great then.. if I have problems with -85 I could downgrade
(04:00:59 PM) agraf__: damjan: definitely - if you're running into gcc3 problems you can always switch in the ignore switch too
(04:01:09 PM) agraf__: damjan: as long as you're not using the cpu emulation parts it's fine
(04:01:20 PM) agraf__: damjan: it was fine
(04:01:21 PM) dachary: pkt: /lib/modules/2.6.29-1-686-bigmem/kernel/drivers/char/hw_random/virtio-rng.ko
(04:01:24 PM) damjan: afaik, I tried that once.. didn't compile
(04:01:26 PM) agraf__: damjan: now it also works with gcc4 ;)
(04:01:27 PM) dachary: indeed ;-)
(04:01:57 PM) damjan: hey .. what's qemu-io ??
(04:04:11 PM) sendro: sorry, im retarded - i was trying to do migrate through virtmanager
(04:04:31 PM) sendro: only avail through "qemu-kvm" console.
(04:04:38 PM) dachary: pkt: do you have a sample XML element that could be used to activate virtio-rng ? 
(04:04:57 PM) dachary: http://libvirt.org/formatdomain.html does not seem to have it
(04:05:02 PM) dachary: hum
(04:05:15 PM) mhiramat_ left the room (quit: Read error: 110 (Connection timed out)).
(04:05:19 PM) dachary: this is not #libvirt, I apologize ;-)
(04:05:33 PM) pkt: dachary: right, I 've never used libvirt so far
(04:06:06 PM) dachary: the kvm option would be what ? 
(04:06:54 PM) dachary: kvm                            72+dfsg-5 probably no good
(04:09:01 PM) dachary: there is a Version: 84+dfsg-2 in Debian experimental. I'm not sure how experimental it is though.
(04:09:19 PM) bier [n=bier@pD9E2EECC.dip.t-dialin.net] entered the room.
(04:11:43 PM) dachary: I have additional confirmation that the tests are indeed blocking on /dev/random
(04:11:53 PM) dachary: python  28507 loic    3r   CHR    1,8      0t0   1546 /dev/random
(04:11:59 PM) dachary: says lsof
(04:12:19 PM) dachary: dev:~# strace -p28507
(04:12:19 PM) dachary: Process 28507 attached - interrupt to quit
(04:12:19 PM) dachary: read(3, ^C <unfinished ...>
(04:12:19 PM) dachary: Process 28507 detached
(04:12:58 PM) dachary: even more motivation to get virtio-rng ;-)
(04:15:47 PM) pkt: it looks like what aliguori was saying is that virtio-rng exists in the kernel but he hasn't implemented it for qemu/kvm
(04:16:19 PM) pkt: so it probably only works for lguest or something
(04:19:18 PM) dachary: ah
(04:19:50 PM) dachary: what does "works for lguest" mean ? 
(04:20:03 PM) pkt: lguest is another hypervisor
(04:23:38 PM) dachary: ok :-)
* follow the steps described at  [[running xorg inside a vserver]] because although you may not plan to run a xorg within a vserver, these modifications allow you to get access to the resources that your application needs to run accelerated
* for the vserver named markerclock
{{{
name=markerclock
echo "/tmp /tmp       none bind 0 0" >> /etc/vservers/$name/fstab
}}}
* restart the vserver and try it with
{{{
apt-get install mesa-utils
DISPLAY=:0 glxinfo
DISPLAY=:0 glxgears
}}}
* There may be problems if the versions of the vserver and the host are different.
Before installing xorg system inside a vserver you need to make the following changes (replace *desktop* with the vserver name):
* Enable following capabilities
{{{
diff -r 511190dd513b -r 0620f9b04fbf etc/vservers/desktop/bcapabilities
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/vservers/desktop/bcapabilities	Wed May 09 14:18:48 2007 +0200
@@ -0,0 +1,7 @@
+CAP_IPC_LOCK
+CAP_IPC_OWNER
+CAP_SYS_RAWIO
+CAP_SYS_ADMIN
+CAP_NET_ADMIN
+CAP_NET_RAW
+CAP_MKNOD
}}}
* Unhide following /proc entries
{{{
diff -r 511190dd513b -r 0620f9b04fbf usr/lib/util-vserver/defaults/vprocunhide-files
--- a/usr/lib/util-vserver/defaults/vprocunhide-files	Wed May 09 14:13:15 2007 +0200
+++ b/usr/lib/util-vserver/defaults/vprocunhide-files	Wed May 09 14:18:48 2007 +0200
@@ -28,3 +28,5 @@
 /proc/uptime
 -/proc/cmdline
 /proc/version
+/proc/mtrr
+/proc/bus/
}}}
* Copy following devices inside the vserver
{{{
name=makerclock
rsync --devices /dev/psaux /var/lib/vservers/$name/dev/
rsync --devices /dev/input/mice /var/lib/vservers/$name/dev/input/
}}}
* routeback on the bridge
* copy two interfaces configuration, the bridge is LAN
* create a directory for each public IP (PUBLIC1 PUBLIC2 etc) with params / rules file
* one DHCP server
* physical eth0 on the same bridget as the VM
invite=http://dachary.org/loic/id_rsa.pub
set -e
author=loic@dachary.org ; app=openssh-server ; apt-get install -y --force-yes $app && hg addremove && hg commit -u $author -m "apt-get install $app"
perl -pi -e 's/^UsePAM/#UsePAM/' /etc/ssh/sshd_config
grep '#UsePAM' /etc/ssh/sshd_config
perl -pi -e 's/^X11UseLocalhost.*/X11UseLocalhost no/' /etc/ssh/sshd_config
if grep 'X11UseLocalhost no' /etc/ssh/sshd_config
then
  perl -pi -e 's/^X11UseLocalhost.*/X11UseLocalhost no/' /etc/ssh/sshd_config
else
  echo 'X11UseLocalhost no' >> /etc/ssh/sshd_config
fi
grep X11UseLocalhost /etc/ssh/sshd_config
app=xbase-clients ; apt-get install -y --force-yes $app && hg addremove && hg commit -u $author -m "apt-get install $app"
ip=$(ifconfig eth0 | grep 'inet add' | tail -1 | sed -e 's/.*addr:\(.*\) Bcast.*/\1/')
echo "$ip $(hostname)" >> /etc/hosts
/etc/init.d/ssh restart
mkdir -p ~/.ssh
chmod 700 ~/.ssh
touch ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
wget -qO - $invite >> ~/.ssh/authorized_keys
http://garden.dachary.org/tiddlyforge.html
* rm /etc/vservers/$name/app/init/mark
* vserver stop $name
* comment out rss feeds
* comment out nagios surveilance
{{{
Migration vserver -> KVM

* Cahier des Charges

  Migrer les vservers "ligamen" et "silva" de la machine
  "yann.fsffrance.org" vers la technologie KVM sur la machine
  "kutsu.ligamen.fr"

  Les 2 nouvelles ips :
  - 87.98.186.139 (ligamen)
  - 87.98.187.140 (silva)

* [29%] Procédure migration

** TODO Questions Proppy

  - Validation taille du swap 1GB
  - Validation reboot kutsu pour test nouvelle config reseau
  - dist-upgrade silva et ligamen because reinstallation pkgs needed
  - Modifs shorewall: sed -i -e s/eth0/br0/ /etc/shorewall/*
  - OK pour ouvrir rsync (873/tcp) dans le firewall ?
  - Netmask et gateway des 2 nouvelles IPs
  - Comment accéder au DNS ?

** TODO Créer daemon rsync

[cyb-tmp]
        uid=root
        path = /var/lib/vservers
        list = no
        hosts deny = *
        hosts allow = 91.121.70.41

$ sudo rsync --daemon

** TODO Ouvrir le firewall pour rsync

...

** DONE Backup à chaud des vservers avec rsync

   root@yann:~# rsync --numeric-ids -aD --del /var/lib/vservers/ligamen ~/backup
   root@yann:~# rsync --numeric-ids -aD --del /var/lib/vservers/silva ~/backup

** [66%] Modification config réseau sur kutsu

*** DONE Sauvegarde /etc/network/interfaces
*** DONE Nouveau /etc/network/interfaces

  - Mettre l'IP de eth0 sur br0
  - Mettre eth0 dans br0

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet manual
        up ifconfig eth0 up

auto br0
iface br0 inet static
      address 91.121.70.41
      netmask 255.255.255.0
      network 91.121.70.0
      broadcast 91.121.70.255
      gateway 91.121.70.254
      bridge_ports eth0
      bridge_stp off
      bridge_maxwait 5

auto eth0:209
iface eth0:209 inet static
      address 87.98.233.209
      netmask 255.255.255.255

*** TODO Adapter tout ce qui dépends de l'IP sur eth0: firewall, etc.

root@kutsu:/etc/shorewall# find -type f | xargs grep eth0
./interfaces:net     eth0            detect          dhcp,tcpflags,routefilter,nosmurfs,logmartians
./masq:eth0                    br0
./91.121.70.41/params:#         NET_IF=eth0
./91.121.70.41/params:#         net     eth0            130.252.100.255 routefilter,norfc1918
./87.98.233.209/params:#                NET_IF=eth0
./87.98.233.209/params:#                net     eth0            130.252.100.255 routefilter,norfc1918
./params:#              NET_IF=eth0
./params:#              net     eth0            130.252.100.255 routefilter,norfc1918
root@kutsu:/etc/shorewall# 

** DONE Identifier la taille disque des vservers actuels

   du -sh /var/lib/vservers/...

   1.8G    /var/lib/vservers/silva
   1.4G    /var/lib/vservers/ligamen

   => 10GB each

** DONE Identifier RAM nécessaire de chaque VM avec Proppy

    => 1GB each

** DONE Créer les volumes logiques

    /dev/all/ligamen /dev/all/silva avec une taille suffisante

    root@kutsu:/etc/network# lvcreate --size 10G -n ligamen all
    Logical volume "ligamen" created
    root@kutsu:/etc/network# lvcreate --size 10G -n silva all
    Logical volume "silva" created
    root@kutsu:/etc/network# 

** DONE Créer les volumes pour le swap

    lvcreate --size 1G -n ligamen-swap all
    lvcreate --size 1G -n silva-swap all

** TODO Préparer les vservers
    apt-get install udev
    Réactiver les initscripts:
    dpkg -S /etc/init.d/* | cut -d: -f1 | sort | uniq | xargs apt-get install --reinstall --assume-yes --force-yes

** TODO Préparation nouveaux FS

*** TODO Ligamen
    vm=ligamen

    mkfs.ext3 /dev/all/$vm
    mount /dev/all/$vm /mnt
    rsync --numeric-ids -a --del yann.fsffrance.org::cyb-tmp/$vm/ /mnt
    vi /mnt/etc/network/interfaces /mnt/etc/resolv.conf
    umount /mnt

*** TODO Silva

    Même chose avec "vm=silva"

**** [0%] Préparer config réseau

***** TODO Ligamen

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
      address 87.98.186.139
      netmask 255.255.255.XXX
      gateway 87.98.186.XXX

search fsffrance.org
nameserver 91.121.70.41
nameserver 213.186.33.99

***** TODO Silva

auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
      address 87.98.187.140
      netmask 255.255.255.XXX
      gateway 87.98.187.XXX

search fsffrance.org
nameserver 91.121.70.41
nameserver 213.186.33.99

** TODO Création du KVM ligamen
  (ajouter le swap)
  vm=ligamen
  virt-install --accelerate --name $vm --ram 1024 --noautoconsole --os-type linux --os-variant debianLenny --network bridge:br0 --vnc --disk path=/dev/all/$vm --disk path=/dev/all/${vm}-swap --cdrom ~cyb/debian-501-i386-netinst.iso
  virsh destroy $vm
  virsh edit $vm
  dans <os> :
    <kernel>/boot/vmlinuz-2.6.26-1-686</kernel>
    <initrd>/boot/initrd.img-2.6.26-1-686</initrd>
    <cmdline>root=/dev/hda rw</cmdline>
  dans <graphics> : listen='0'
  virsh start $vm

** TODO Création du KVM silva

   Même chose avec vm=silva

** TODO Tester que tout marche

** TODO Migration DNS

   Voir Loïc

** TODO Synchro finale ligamen
   Sur Yann
   vm=ligamen
   vserver $vm stop

   Sur Kutsu
   vm=ligamen
   virsh destroy $vm
   mount /dev/all/$vm /mnt
   rsync --numeric-ids -a --del yann.fsffrance.org::cyb-tmp/$vm/ /mnt
   vi /mnt/etc/network/interfaces /mnt/etc/resolv.conf
   umount /mnt
   virsh start $vm

** TODO Synchro finale silva

   Même chose avec vm=silva

** TODO Supprimer daemon rsync
   rm /etc/rsyncd.conf
   killall rsync
}}}
* ''With ssh access to the vserver host''
<<<
Copy the remote vserver verbatim using an rsync command such as the following
{{{
rsync --delete --exclude=/dev --include=/var/www --exclude=/var/* --exclude=/sys --exclude=/proc  -av --numeric-ids root@pecho.fsffrance.org:/var/lib/vservers/pokersource/ pokersource/ 
}}}

Omit the {{{--delete}}} when running for the first time. Always try with {{{--dry-run}}} in both cases.
<<<
* ''No ssh access requires rsync access to root''
<<<
Using basically the same command as above with a rsync source. The rsync daemon must be running on the software appliance. Add the following stanza in the {{{/etc/rsyncd.conf}}}:
{{{
[root]
        comment = openscenegraph.dachary.org root (RO,8GB)
        path = /
        uid = root
        max connections = 1
        exclude = /proc
        read only = yes
}}}
and don't forget to update {{{/etc/default/rsync}}} or {{{/etc/init.d/rsync start}}} won't do anything.
<<<
Don't try to use mercurial to get a working copy : it won't work.
When modifying the working copy, use mercurial often to commit the modifications. If the changes are suitable for mercurial {{{hg push}}} them to remote vserver when they are complete. Otherwise stop the remote vserver, resynchronize with rsync and make sure the local changes are not trashed. Check that the changes still work on the updated copy and rsync the working copy to the remote vserver. Relaunch the remote vserver when done.